// xlocale internal header (from <locale>)
#pragma once
#ifndef _XLOCALE_
#define _XLOCALE_
#ifndef RC_INVOKED
#include <climits>
#include <cstring>
#include <memory>
#include <typeinfo>
#include <xfacet>
#include <xlocinfo>

#pragma pack(push, _CRT_PACKING)
#pragma warning(push, _STL_WARNING_LEVEL)
#pragma warning(disable : _STL_DISABLED_WARNINGS)
_STL_DISABLE_CLANG_WARNINGS
#pragma push_macro("new")
#undef new

_STD_BEGIN
// CLASS TEMPLATE _Locbase
template <class _Dummy>
class _Locbase { // define templatized category constants, instantiate on demand
public:
    _PGLOBAL static const int collate  = _M_COLLATE;
    _PGLOBAL static const int ctype    = _M_CTYPE;
    _PGLOBAL static const int monetary = _M_MONETARY;
    _PGLOBAL static const int numeric  = _M_NUMERIC;
    _PGLOBAL static const int time     = _M_TIME;
    _PGLOBAL static const int messages = _M_MESSAGES;
    _PGLOBAL static const int all      = _M_ALL;
    _PGLOBAL static const int none     = 0;
};

template <class _Dummy>
const int _Locbase<_Dummy>::collate;
template <class _Dummy>
const int _Locbase<_Dummy>::ctype;
template <class _Dummy>
const int _Locbase<_Dummy>::monetary;
template <class _Dummy>
const int _Locbase<_Dummy>::numeric;
template <class _Dummy>
const int _Locbase<_Dummy>::time;
template <class _Dummy>
const int _Locbase<_Dummy>::messages;
template <class _Dummy>
const int _Locbase<_Dummy>::all;
template <class _Dummy>
const int _Locbase<_Dummy>::none;

// CLASS locale
template <class _Elem>
class collate;

struct _CRTIMP2_PURE_IMPORT _Crt_new_delete { // base class for marking allocations as CRT blocks
#ifdef _DEBUG
    void* __CLRCALL_OR_CDECL operator new(size_t _Size) { // replace operator new
        void* _Ptr = operator new(_Size, nothrow);
        if (!_Ptr) {
            _Xbad_alloc();
        }

        return _Ptr;
    }

    void* __CLRCALL_OR_CDECL operator new(size_t _Size, const nothrow_t&) noexcept { // replace nothrow operator new
        return _malloc_dbg(_Size > 0 ? _Size : 1, _CRT_BLOCK, __FILE__, __LINE__);
    }

    void __CLRCALL_OR_CDECL operator delete(void* _Ptr) noexcept { // replace operator delete
        _CSTD free(_Ptr);
    }

    void __CLRCALL_OR_CDECL operator delete(void* _Ptr, const nothrow_t&) noexcept { // replace nothrow operator delete
        operator delete(_Ptr);
    }

    void* __CLRCALL_OR_CDECL operator new(size_t, void* _Ptr) noexcept { // imitate True Placement New
        return _Ptr;
    }

    void __CLRCALL_OR_CDECL operator delete(void*, void*) noexcept { // imitate True Placement Delete
    }
#endif // _DEBUG
};

class locale : public _Locbase<int>, public _Crt_new_delete { // nonmutable collection of facets that describe a locale
public:
    using category = int;

    // CLASS id
    class _CRTIMP2_PURE_IMPORT id { // identifier stamp, unique for each distinct kind of facet
    public:
        __CLR_OR_THIS_CALL id(size_t _Val = 0) : _Id(_Val) { // construct with specified stamp value
        }

        __CLR_OR_THIS_CALL operator size_t() { // get stamp, with lazy allocation
            if (_Id == 0) { // still zero, allocate stamp
                _BEGIN_LOCK(_LOCK_LOCALE)
                if (_Id == 0) {
                    _Id = static_cast<size_t>(++_Id_cnt);
                }
                _END_LOCK()
            }
            return _Id;
        }

    private:
        size_t _Id; // the identifier stamp

        __PURE_APPDOMAIN_GLOBAL static int _Id_cnt;

    public:
        __CLR_OR_THIS_CALL id(const id&) = delete;
        id& __CLR_OR_THIS_CALL operator=(const id&) = delete;
    };

    class _Locimp;

    // CLASS facet
    class _CRTIMP2_PURE_IMPORT facet
        : public _Facet_base,
          public _Crt_new_delete { // base class for all locale facets, performs reference counting
    private:
        friend struct _Facet_guard;

    public:
        static size_t __CLRCALL_OR_CDECL _Getcat(const facet** = nullptr,
            const locale* = nullptr) { // get category value, or -1 if no corresponding C category
            return static_cast<size_t>(-1);
        }

        virtual void __CLR_OR_THIS_CALL _Incref() noexcept override { // increment use count
            _MT_INCR(_Myrefs);
        }

        virtual _Facet_base* __CLR_OR_THIS_CALL _Decref() noexcept override { // decrement use count
            if (_MT_DECR(_Myrefs) == 0) {
                return this;
            }

            return nullptr;
        }

    private:
        _Atomic_counter_t _Myrefs; // the reference count

    protected:
        explicit __CLR_OR_THIS_CALL facet(size_t _Initrefs = 0)
            : _Myrefs(static_cast<_Atomic_counter_t>(_Initrefs)) // non-atomic initialization
        { // construct with initial reference count
        }

        virtual __CLR_OR_THIS_CALL ~facet() noexcept { // ensure that derived classes can be destroyed properly
        }

    public:
        __CLR_OR_THIS_CALL facet(const facet&) = delete;
        facet& __CLR_OR_THIS_CALL operator=(const facet&) = delete;
    };

    struct _Facet_guard {
        facet* _Target;
        ~_Facet_guard() {
            if (_Target) {
                delete _Target->_Decref();
            }
        }
    };

    // CLASS _Locimp
    class _CRTIMP2_PURE_IMPORT _Locimp : public facet { // reference-counted actual implementation of a locale
    protected:
        __CLR_OR_THIS_CALL ~_Locimp() noexcept { // destroy the object
            _Locimp_dtor(this);
        }

    private:
        static _MRTIMP2_PURE_NPURE _Locimp* __CLRCALL_PURE_OR_CDECL _New_Locimp(bool _Transparent = false);
        static _MRTIMP2_PURE_NPURE _Locimp* __CLRCALL_PURE_OR_CDECL _New_Locimp(const _Locimp& _Right);

        static _MRTIMP2_PURE_NPURE void __CLRCALL_PURE_OR_CDECL _Locimp_dtor(_Locimp*);
        static _MRTIMP2_PURE_NPURE void __CLRCALL_PURE_OR_CDECL _Locimp_Addfac(_Locimp*, facet*, size_t); // add a facet
        static void __CLRCALL_PURE_OR_CDECL _Locimp_ctor(_Locimp*, const _Locimp&);

        friend locale;

        __CLR_OR_THIS_CALL _Locimp(bool _Transparent)
            : locale::facet(1), _Facetvec(nullptr), _Facetcount(0), _Catmask(none), _Xparent(_Transparent),
              _Name("*") { // construct an empty _Locimp
        }

        __CLR_OR_THIS_CALL _Locimp(const _Locimp& _Right)
            : locale::facet(1), _Facetvec(nullptr), _Facetcount(_Right._Facetcount), _Catmask(_Right._Catmask),
              _Xparent(_Right._Xparent), _Name(_Right._Name.c_str()) { // construct by copying
            _Locimp_ctor(this, _Right);
        }

        void __CLR_OR_THIS_CALL _Addfac(facet* _Pfacet, size_t _Id) { // add a facet
            _Locimp_Addfac(this, _Pfacet, _Id);
        }

        static _Locimp* __CLRCALL_OR_CDECL _Makeloc(
            const _Locinfo&, category, _Locimp*, const locale*); // make essential facets

        static void __CLRCALL_OR_CDECL _Makewloc(
            const _Locinfo&, category, _Locimp*, const locale*); // make wchar_t facets

#ifdef _NATIVE_WCHAR_T_DEFINED
        static void __CLRCALL_OR_CDECL _Makeushloc(
            const _Locinfo&, category, _Locimp*, const locale*); // make ushort facets
#endif // _NATIVE_WCHAR_T_DEFINED

        static void __CLRCALL_OR_CDECL _Makexloc(
            const _Locinfo&, category, _Locimp*, const locale*); // make remaining facets

        facet** _Facetvec; // pointer to vector of facets
        size_t _Facetcount; // size of vector of facets
        category _Catmask; // mask describing implemented categories
        bool _Xparent; // true if locale is transparent
        _Yarn<char> _Name; // locale name, or "*" if not known

        __PURE_APPDOMAIN_GLOBAL static _Locimp* _Clocptr;

    public:
        _Locimp& __CLR_OR_THIS_CALL operator=(const _Locimp&) = delete;
    };

    template <class _Elem, class _Traits, class _Alloc>
    bool operator()(
        const basic_string<_Elem, _Traits, _Alloc>& _Left, const basic_string<_Elem, _Traits, _Alloc>& _Right)
        const { // compare _Left and _Right strings using collate facet in locale
        const auto& _Coll_fac = use_facet<_STD collate<_Elem>>(*this);

        return _Coll_fac.compare(
                   _Left.c_str(), _Left.c_str() + _Left.size(), _Right.c_str(), _Right.c_str() + _Right.size())
               < 0;
    }

    template <class _Facet>
    locale combine(const locale& _Loc) const { // combine two locales
        _Facet* _Facptr;

        _TRY_BEGIN
        _Facptr = (_Facet*) &use_facet<_Facet>(_Loc);
        _CATCH_ALL
        _Xruntime_error("locale::combine facet missing");
        _CATCH_END

        _Locimp* _Newimp = _Locimp::_New_Locimp(*_Ptr);
        _Newimp->_Addfac(_Facptr, _Facet::id);
        _Newimp->_Catmask = none;
        _Newimp->_Name    = "*";
        return locale(_Newimp);
    }

    template <class _Facet>
    locale(const locale& _Loc, const _Facet* _Facptr)
        : _Ptr(_Locimp::_New_Locimp(*_Loc._Ptr)) { // construct from _Loc, replacing facet with *_Facptr
        if (_Facptr != nullptr) { // replace facet
            _Ptr->_Addfac((_Facet*) _Facptr, _Facet::id);
            _Ptr->_Catmask = none;
            _Ptr->_Name    = "*";
        }
    }

    locale(_Uninitialized) { // defer construction
    }

    locale(const locale& _Right) noexcept : _Ptr(_Right._Ptr) { // construct by copying
        _Ptr->_Incref();
    }

    locale() noexcept : _Ptr(_Init(true)) { // construct from current locale
    }

#if !defined(MRTDLL) || !defined(_CRTBLD)
    locale(const locale& _Loc, const locale& _Other,
        category _Cat)
        : _Ptr(_Locimp::_New_Locimp(*_Loc._Ptr)) { // construct a locale by copying named facets
        if (_Cat != none) { // worth adding, do it
            _Facet_guard _Guard{_Ptr};
            _BEGIN_LOCINFO(_Lobj)
            _Locimp::_Makeloc(_Lobj, _Cat, _Ptr, &_Other);
            _Lobj._Addcats(_Loc._Ptr->_Catmask, _Loc.name().c_str());
            _Lobj._Addcats(_Other._Ptr->_Catmask, _Other.name().c_str());
            _Ptr->_Catmask = _Loc._Ptr->_Catmask | _Other._Ptr->_Catmask;
            _Ptr->_Name    = _Lobj._Getname();
            _END_LOCINFO()
            _Guard._Target = nullptr;
        }
    }

private:
    void _Construct(const string& _Str,
        category _Cat) { // construct a locale with named facets
        bool _Bad = false;
        _Init();
        if (_Cat != none) { // worth adding, do it
            _Facet_guard _Guard{_Ptr};
            _BEGIN_LOCINFO(_Lobj(_Cat, _Str.c_str()))
            if (_Badname(_Lobj)) {
                _Bad = true;
            } else { // name okay, build the locale
                _Locimp::_Makeloc(_Lobj, _Cat, _Ptr, nullptr);
                _Ptr->_Catmask = _Cat;
                _Ptr->_Name    = _Str.c_str();
            }
            _END_LOCINFO()
            _Guard._Target = nullptr;
        }

        if (_Bad) { // Don't throw within _BEGIN_LOCINFO if we can avoid it
            delete _Ptr->_Decref();
            _Xruntime_error("bad locale name");
        }
    }

public:
    explicit locale(const char* _Locname,
        category _Cat = all)
        : _Ptr(_Locimp::_New_Locimp()) { // construct a locale with named facets
        // _Locname might have been returned from setlocale().
        // Therefore, _Construct() takes const string&.
        if (_Locname == nullptr) {
            _Xruntime_error("bad locale name");
        }

        _Construct(_Locname, _Cat);
    }

    locale(const locale& _Loc, const char* _Locname,
        category _Cat)
        : _Ptr(_Locimp::_New_Locimp(*_Loc._Ptr)) { // construct a locale by copying, replacing named facets
        // _Locname might have been returned from setlocale().
        // Therefore, _Construct() takes const string&.
        if (_Locname == nullptr) {
            _Xruntime_error("bad locale name");
        }

        _Construct(_Locname, _Cat);
    }

    explicit locale(const string& _Str,
        category _Cat = all)
        : _Ptr(_Locimp::_New_Locimp()) { // construct a locale with named facets
        _Construct(_Str, _Cat);
    }

    locale(const locale& _Loc, const string& _Str,
        category _Cat)
        : _Ptr(_Locimp::_New_Locimp(*_Loc._Ptr)) { // construct a locale by copying, replacing named facets
        _Construct(_Str, _Cat);
    }
#endif // !MRTDLL || !_CRTBLD

    ~locale() noexcept { // destroy the object
        if (_Ptr != nullptr) {
            delete _Ptr->_Decref();
        }
    }

    locale& operator=(const locale& _Right) noexcept { // assign a locale

        if (_Ptr != _Right._Ptr) { // different implementation, point at new one
            delete _Ptr->_Decref();
            _Ptr = _Right._Ptr;
            _Ptr->_Incref();
        }
        return *this;
    }

    string name() const { // return locale name
        return _Ptr == nullptr ? string() : _Ptr->_Name.c_str();
    }

    _Ret_z_ const char* c_str() const { // return locale name as NTBS
        return _Ptr == nullptr ? "" : _Ptr->_Name.c_str();
    }

    const facet* _Getfacet(size_t _Id) const { // look up a facet in locale object
        const facet* _Facptr = _Id < _Ptr->_Facetcount ? _Ptr->_Facetvec[_Id] : nullptr; // null if id off end
        if (_Facptr != nullptr || !_Ptr->_Xparent) {
            return _Facptr; // found facet or not transparent
        } else { // look in current locale
            locale::_Locimp* _Ptr0 = _Getgloballocale();
            return _Id < _Ptr0->_Facetcount ? _Ptr0->_Facetvec[_Id] // get from current locale
                                            : nullptr; // no entry in current locale
        }
    }

    _NODISCARD bool operator==(const locale& _Loc) const { // compare locales for equality
        return _Ptr == _Loc._Ptr || (name().compare("*") != 0 && name().compare(_Loc.name()) == 0);
    }

    _NODISCARD bool operator!=(const locale& _Right) const { // test for locale inequality
        return !(*this == _Right);
    }

    static _MRTIMP2_PURE const locale& __CLRCALL_PURE_OR_CDECL classic(); // classic "C" locale

    static _MRTIMP2_PURE locale __CLRCALL_PURE_OR_CDECL global(const locale&); // current locale

    static _MRTIMP2_PURE locale __CLRCALL_PURE_OR_CDECL empty(); // empty (transparent) locale

private:
    locale(_Locimp* _Ptrimp) : _Ptr(_Ptrimp) { // construct from _Locimp pointer
    }

    static _MRTIMP2_PURE _Locimp* __CLRCALL_PURE_OR_CDECL _Init(bool _Do_incref = false); // initialize locale
    static _MRTIMP2_PURE _Locimp* __CLRCALL_PURE_OR_CDECL _Getgloballocale();
    static _MRTIMP2_PURE void __CLRCALL_PURE_OR_CDECL _Setgloballocale(void*);

    bool _Badname(const _Locinfo& _Lobj) { // test if name is "*"
        return _CSTD strcmp(_Lobj._Getname(), "*") == 0;
    }

    _Locimp* _Ptr; // pointer to locale implementation object
};

// SUPPORT TEMPLATES
template <class _Facet>
struct _Facetptr { // store pointer to lazy facet for use_facet
    __PURE_APPDOMAIN_GLOBAL static const locale::facet* _Psave;
};

template <class _Facet>
__PURE_APPDOMAIN_GLOBAL const locale::facet* _Facetptr<_Facet>::_Psave = nullptr;

template <class _Facet>
inline const _Facet& __CRTDECL use_facet(const locale& _Loc)

{ // get facet reference from locale
    _BEGIN_LOCK(_LOCK_LOCALE) // the thread lock, make get atomic
    const locale::facet* _Psave = _Facetptr<_Facet>::_Psave; // static pointer to lazy facet

    const size_t _Id         = _Facet::id;
    const locale::facet* _Pf = _Loc._Getfacet(_Id);

    if (_Pf == nullptr) {
        if (_Psave != nullptr) {
            _Pf = _Psave; // lazy facet already allocated
        } else if (_Facet::_Getcat(&_Psave, &_Loc) == static_cast<size_t>(-1)) {
#if _HAS_EXCEPTIONS
            _THROW(bad_cast{}); // lazy disallowed
#else // _HAS_EXCEPTIONS
            abort(); // lazy disallowed
#endif // _HAS_EXCEPTIONS
        } else { // queue up lazy facet for destruction
            auto _Pfmod = const_cast<locale::facet*>(_Psave);
            unique_ptr<_Facet_base> _Psave_guard(static_cast<_Facet_base*>(_Pfmod));

#if defined(_M_CEE)
            _Facet_Register_m(_Pfmod);
#else // defined(_M_CEE)
            _Facet_Register(_Pfmod);
#endif // defined(_M_CEE)

            _Pfmod->_Incref();
            _Facetptr<_Facet>::_Psave = _Psave;
            _Pf                       = _Psave;

            (void) _Psave_guard.release();
        }
    }

    return static_cast<const _Facet&>(*_Pf); // should be dynamic_cast
    _END_LOCK()
} // end of use_facet body

// FUNCTION TEMPLATE _Getloctxt
template <class _Elem, class _InIt>
inline int __CRTDECL _Getloctxt(_InIt& _First, _InIt& _Last, size_t _Numfields,
    const _Elem* _Ptr) { // find field at _Ptr that matches longest in [_First, _Last)
    for (size_t _Off = 0; _Ptr[_Off] != (_Elem) 0; ++_Off) {
        if (_Ptr[_Off] == _Ptr[0]) {
            ++_Numfields; // add fields with leading mark to initial count
        }
    }

    string _Str(_Numfields, '\0'); // one column counter for each field

    int _Ans = -2; // no candidates so far
    for (size_t _Column = 1;; ++_Column, (void) ++_First, _Ans = -1) { // test each element against all viable fields
        bool _Prefix  = false; // seen at least one valid prefix
        size_t _Off   = 0; // offset into fields
        size_t _Field = 0; // current field number

        for (; _Field < _Numfields; ++_Field) { // test element at _Column in field _Field
            while (_Ptr[_Off] != (_Elem) 0 && _Ptr[_Off] != _Ptr[0]) { // find beginning of field
                ++_Off;
            }

            if (_Str[_Field] != '\0') {
                _Off += _Str[_Field]; // skip tested columns in field
            } else if (_Ptr[_Off += _Column] == _Ptr[0]
                       || _Ptr[_Off] == (_Elem) 0) { // matched all of field, save as possible answer
                _Str[_Field] = (char) (_Column < 127 ? _Column : 127); // save skip count if small enough
                _Ans         = (int) _Field; // save answer
            } else if (_First == _Last || _Ptr[_Off] != *_First) {
                _Str[_Field] = (char) (_Column < 127 ? _Column : 127); // no match, just save skip count
            } else {
                _Prefix = true; // still a valid prefix
            }
        }

        if (!_Prefix || _First == _Last) {
            break; // no pending prefixes or no input, give up
        }
    }
    return _Ans; // return field number or negative value on failure
}

// FUNCTION TEMPLATE _Maklocbyte
template <class _Elem>
inline char __CRTDECL _Maklocbyte(_Elem _Char,
    const _Locinfo::_Cvtvec&) { // convert _Elem to char using _Cvtvec
    return (char) (unsigned char) _Char;
}

template <>
inline char __CRTDECL _Maklocbyte(wchar_t _Char,
    const _Locinfo::_Cvtvec& _Cvt) { // convert wchar_t to char using _Cvtvec
    char _Byte       = '\0';
    mbstate_t _Mbst1 = {};
    _Wcrtomb(&_Byte, _Char, &_Mbst1, &_Cvt);
    return _Byte;
}

#ifdef _NATIVE_WCHAR_T_DEFINED
template <>
inline char __CRTDECL _Maklocbyte(unsigned short _Char,
    const _Locinfo::_Cvtvec& _Cvt) { // convert unsigned short to char using _Cvtvec
    char _Byte       = '\0';
    mbstate_t _Mbst1 = {};
    _Wcrtomb(&_Byte, (wchar_t) _Char, &_Mbst1, &_Cvt);
    return _Byte;
}
#endif // _NATIVE_WCHAR_T_DEFINED

// FUNCTION TEMPLATE _Maklocchr
template <class _Elem>
inline _Elem __CRTDECL _Maklocchr(char _Byte, _Elem*,
    const _Locinfo::_Cvtvec&) { // convert char to _Elem using _Cvtvec
    return (_Elem)(unsigned char) _Byte;
}

template <>
inline wchar_t __CRTDECL _Maklocchr(char _Byte, wchar_t*,
    const _Locinfo::_Cvtvec& _Cvt) { // convert char to wchar_t using _Cvtvec
    wchar_t _Wc      = L'\0';
    mbstate_t _Mbst1 = {};
    _Mbrtowc(&_Wc, &_Byte, 1, &_Mbst1, &_Cvt);
    return _Wc;
}

#ifdef _NATIVE_WCHAR_T_DEFINED
template <>
inline unsigned short __CRTDECL _Maklocchr(char _Byte, unsigned short*,
    const _Locinfo::_Cvtvec& _Cvt) { // convert char to unsigned short using _Cvtvec
    unsigned short _Wc = (unsigned short) 0;
    mbstate_t _Mbst1   = {};
    _Mbrtowc((wchar_t*) &_Wc, &_Byte, 1, &_Mbst1, &_Cvt);
    return _Wc;
}
#endif // _NATIVE_WCHAR_T_DEFINED

// FUNCTION TEMPLATE _Maklocstr
template <class _Elem>
inline _Elem* __CRTDECL _Maklocstr(const char* _Ptr, _Elem*,
    const _Locinfo::_Cvtvec&) { // convert C string to _Elem sequence using _Cvtvec
    size_t _Count = _CSTD strlen(_Ptr) + 1;

    _Elem* _Ptrdest = (_Elem*) _calloc_dbg(_Count, sizeof(_Elem), _CRT_BLOCK, __FILE__, __LINE__);

    if (!_Ptrdest) {
        _Xbad_alloc();
    }

    for (_Elem* _Ptrnext = _Ptrdest; 0 < _Count; --_Count, ++_Ptrnext, ++_Ptr) {
        *_Ptrnext = (_Elem)(unsigned char) *_Ptr;
    }

    return _Ptrdest;
}

template <>
inline wchar_t* __CRTDECL _Maklocstr(const char* _Ptr, wchar_t*,
    const _Locinfo::_Cvtvec& _Cvt) { // convert C string to wchar_t sequence using _Cvtvec
    size_t _Count, _Count1;
    size_t _Wchars;
    const char* _Ptr1;
    int _Bytes;
    wchar_t _Wc;
    mbstate_t _Mbst1 = {};

    _Count1 = _CSTD strlen(_Ptr) + 1;
    for (_Count = _Count1, _Wchars = 0, _Ptr1 = _Ptr; 0 < _Count; _Count -= _Bytes, _Ptr1 += _Bytes, ++_Wchars) {
        if ((_Bytes = _Mbrtowc(&_Wc, _Ptr1, _Count, &_Mbst1, &_Cvt)) <= 0) {
            break;
        }
    }

    ++_Wchars; // count terminating nul

    wchar_t* _Ptrdest = (wchar_t*) _calloc_dbg(_Wchars, sizeof(wchar_t), _CRT_BLOCK, __FILE__, __LINE__);

    if (!_Ptrdest) {
        _Xbad_alloc();
    }

    wchar_t* _Ptrnext = _Ptrdest;
    mbstate_t _Mbst2  = {};

    for (; 0 < _Wchars; _Count -= _Bytes, _Ptr += _Bytes, --_Wchars, ++_Ptrnext) {
        if ((_Bytes = _Mbrtowc(_Ptrnext, _Ptr, _Count1, &_Mbst2, &_Cvt)) <= 0) {
            break;
        }
    }

    *_Ptrnext = L'\0';

    return _Ptrdest;
}

#ifdef _NATIVE_WCHAR_T_DEFINED
template <>
inline unsigned short* __CRTDECL _Maklocstr(const char* _Ptr, unsigned short*,
    const _Locinfo::_Cvtvec& _Cvt) { // convert C string to unsigned short sequence using _Cvtvec
    size_t _Count, _Count1;
    size_t _Wchars;
    const char* _Ptr1;
    int _Bytes;
    unsigned short _Wc;
    mbstate_t _Mbst1 = {};

    _Count1 = _CSTD strlen(_Ptr) + 1;
    for (_Count = _Count1, _Wchars = 0, _Ptr1 = _Ptr; 0 < _Count; _Count -= _Bytes, _Ptr1 += _Bytes, ++_Wchars) {
        if ((_Bytes = _Mbrtowc((wchar_t*) &_Wc, _Ptr1, _Count, &_Mbst1, &_Cvt)) <= 0) {
            break;
        }
    }

    ++_Wchars; // count terminating nul

    wchar_t* _Ptrdest = (wchar_t*) _calloc_dbg(_Wchars, sizeof(wchar_t), _CRT_BLOCK, __FILE__, __LINE__);

    if (!_Ptrdest) {
        _Xbad_alloc();
    }

    wchar_t* _Ptrnext = _Ptrdest;
    mbstate_t _Mbst2  = {};
    for (; 0 < _Wchars; _Count -= _Bytes, _Ptr += _Bytes, --_Wchars, ++_Ptrnext) {
        if ((_Bytes = _Mbrtowc(_Ptrnext, _Ptr, _Count1, &_Mbst2, &_Cvt)) <= 0) {
            break;
        }
    }

    *_Ptrnext = L'\0';
    return (unsigned short*) _Ptrdest;
}
#endif // _NATIVE_WCHAR_T_DEFINED

// STRUCT codecvt_base
class _CRTIMP2_PURE_IMPORT codecvt_base : public locale::facet { // base class for codecvt
public:
    enum { // constants for different parse states
        ok,
        partial,
        error,
        noconv
    };
    using result = int;

    __CLR_OR_THIS_CALL codecvt_base(size_t _Refs = 0) : locale::facet(_Refs) { // default constructor
    }

    bool __CLR_OR_THIS_CALL always_noconv() const
        noexcept { // return true if conversions never change input (from codecvt)
        return do_always_noconv();
    }

    int __CLR_OR_THIS_CALL max_length() const
        noexcept { // return maximum length required for a conversion (from codecvt)
        return do_max_length();
    }

    int __CLR_OR_THIS_CALL encoding() const noexcept { // return length of code sequence (from codecvt)
        return do_encoding();
    }

    __CLR_OR_THIS_CALL ~codecvt_base() noexcept { // destroy the object
    }

protected:
    virtual bool __CLR_OR_THIS_CALL do_always_noconv() const
        noexcept { // return true if conversions never change input (from codecvt)
        return false;
    }

    virtual int __CLR_OR_THIS_CALL do_max_length() const
        noexcept { // return maximum length required for a conversion (from codecvt)
        return 1;
    }

    virtual int __CLR_OR_THIS_CALL do_encoding() const noexcept { // return length of code sequence (from codecvt)
        return 1; // -1 ==> state dependent, 0 ==> varying length
    }
};

// CLASS TEMPLATE codecvt
template <class _Elem, class _Byte,
    class _Statype>
class codecvt : public codecvt_base { // facet for converting between _Elem and char (_Byte) sequences
public:
    // Explicitly specialized below:
    // codecvt<wchar_t, char, mbstate_t>
    // codecvt<unsigned short, char, mbstate_t>
    // codecvt<char16_t, char, mbstate_t> (extension)
    // codecvt<char32_t, char, mbstate_t> (extension)

    // __cpp_char8_t
    // codecvt<char16_t, char8_t, mbstate_t>
    // codecvt<char32_t, char8_t, mbstate_t>
    static_assert(!_ENFORCE_FACET_SPECIALIZATIONS || is_same_v<codecvt, codecvt<char, char, mbstate_t>>,
        _FACET_SPECIALIZATION_MESSAGE);

    using intern_type = _Elem;
    using extern_type = _Byte;
    using state_type  = _Statype;

    result __CLR_OR_THIS_CALL in(_Statype& _State, const _Byte* _First1, const _Byte* _Last1, const _Byte*& _Mid1,
        _Elem* _First2, _Elem* _Last2, _Elem*& _Mid2) const { // convert bytes [_First1, _Last1) to [_First2, _Last)
        return do_in(_State, _First1, _Last1, _Mid1, _First2, _Last2, _Mid2);
    }

    result __CLR_OR_THIS_CALL out(_Statype& _State, const _Elem* _First1, const _Elem* _Last1, const _Elem*& _Mid1,
        _Byte* _First2, _Byte* _Last2, _Byte*& _Mid2) const { // convert [_First1, _Last1) to bytes [_First2, _Last2)
        return do_out(_State, _First1, _Last1, _Mid1, _First2, _Last2, _Mid2);
    }

    result __CLR_OR_THIS_CALL unshift(_Statype& _State, _Byte* _First2, _Byte* _Last2,
        _Byte*& _Mid2) const { // generate bytes to return to default shift state
        return do_unshift(_State, _First2, _Last2, _Mid2);
    }

    int __CLR_OR_THIS_CALL length(_Statype& _State, const _Byte* _First1, const _Byte* _Last1,
        size_t _Count) const { // return min(_Count, converted length of bytes [_First1, _Last1))
        return do_length(_State, _First1, _Last1, _Count);
    }

    __PURE_APPDOMAIN_GLOBAL static locale::id id; // unique facet id

    explicit __CLR_OR_THIS_CALL codecvt(size_t _Refs = 0) : codecvt_base(_Refs) { // construct from current locale
        _Init(_Locinfo());
    }

    __CLR_OR_THIS_CALL codecvt(const _Locinfo& _Lobj, size_t _Refs = 0)
        : codecvt_base(_Refs) { // construct from specified locale
        _Init(_Lobj);
    }

    static size_t __CLRCALL_OR_CDECL _Getcat(const locale::facet** _Ppf = nullptr,
        const locale* _Ploc = nullptr) { // return locale category mask and construct standard facet
        if (_Ppf != nullptr && *_Ppf == nullptr) {
            *_Ppf = new codecvt<_Elem, _Byte, _Statype>(_Locinfo(_Ploc->c_str()));
        }

        return _X_CTYPE;
    }

protected:
    virtual __CLR_OR_THIS_CALL ~codecvt() noexcept { // destroy the object
    }

    void __CLR_OR_THIS_CALL _Init(const _Locinfo&) { // initialize from _Locinfo object
    }

    virtual bool __CLR_OR_THIS_CALL do_always_noconv() const
        noexcept { // return true if conversions never change input (from codecvt)
        return is_same_v<_Byte, _Elem>;
    }

    virtual result __CLR_OR_THIS_CALL do_in(_Statype&, const _Byte* _First1, const _Byte* _Last1, const _Byte*& _Mid1,
        _Elem* _First2, _Elem* _Last2, _Elem*& _Mid2) const { // convert bytes [_First1, _Last1) to [_First2, _Last)
        _Mid1 = _First1;
        _Mid2 = _First2;
        if (is_same_v<_Byte, _Elem>) {
            return noconv; // convert nothing
        }

        // types differ, copy one for one
        for (; _Mid1 != _Last1 && _Mid2 != _Last2; ++_Mid1, ++_Mid2) {
            *_Mid2 = (_Elem) *_Mid1;
        }

        return ok;
    }

    virtual result __CLR_OR_THIS_CALL do_out(_Statype&, const _Elem* _First1, const _Elem* _Last1, const _Elem*& _Mid1,
        _Byte* _First2, _Byte* _Last2, _Byte*& _Mid2) const { // convert [_First1, _Last1) to bytes [_First2, _Last)
        _Mid1 = _First1;
        _Mid2 = _First2;
        if (is_same_v<_Byte, _Elem>) {
            return noconv; // convert nothing
        }

        // types differ, copy one for one
        for (; _Mid1 != _Last1 && _Mid2 != _Last2; ++_Mid1, ++_Mid2) {
            *_Mid2 = (_Byte) *_Mid1;
        }

        return ok;
    }

    virtual result __CLR_OR_THIS_CALL do_unshift(
        _Statype&, _Byte* _First2, _Byte*, _Byte*& _Mid2) const { // generate bytes to return to default shift state
        _Mid2 = _First2;
        return noconv; // convert nothing
    }

    virtual int __CLR_OR_THIS_CALL do_length(_Statype&, const _Byte* _First1, const _Byte* _Last1,
        size_t _Count) const { // return min(_Count, converted length of bytes [_First1, _Last1))
        return static_cast<int>(_Min_value(_Count, static_cast<size_t>(_Last1 - _First1))); // assumes 1:1 conversion
    }
};

// STATIC codecvt::id OBJECT
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdllimport-static-field-def"
#endif // __clang__

template <class _Elem, class _Byte, class _Statype>
__PURE_APPDOMAIN_GLOBAL locale::id codecvt<_Elem, _Byte, _Statype>::id;

#ifdef __clang__
#pragma clang diagnostic pop
#endif // __clang__

// ENUM _Codecvt_mode
enum _Codecvt_mode { _Consume_header = 4, _Generate_header = 2 };

// CLASS codecvt<char16_t, char, _Mbstatet>
template <>
class _CRTIMP2_PURE_IMPORT codecvt<char16_t, char, _Mbstatet>
    : public codecvt_base { // facet for converting between char16_t and UTF-8 byte sequences
public:
    using _Mybase     = codecvt<char16_t, char, _Mbstatet>;
    using _Elem       = char16_t;
    using _Byte       = char;
    using _Statype    = _Mbstatet;
    using intern_type = _Elem;
    using extern_type = _Byte;
    using state_type  = _Statype;

    result __CLR_OR_THIS_CALL in(_Statype& _State, const _Byte* _First1, const _Byte* _Last1, const _Byte*& _Mid1,
        _Elem* _First2, _Elem* _Last2, _Elem*& _Mid2) const { // convert bytes [_First1, _Last1) to [_First2, _Last)
        return do_in(_State, _First1, _Last1, _Mid1, _First2, _Last2, _Mid2);
    }

    result __CLR_OR_THIS_CALL out(_Statype& _State, const _Elem* _First1, const _Elem* _Last1, const _Elem*& _Mid1,
        _Byte* _First2, _Byte* _Last2, _Byte*& _Mid2) const { // convert [_First1, _Last1) to bytes [_First2, _Last)
        return do_out(_State, _First1, _Last1, _Mid1, _First2, _Last2, _Mid2);
    }

    result __CLR_OR_THIS_CALL unshift(_Statype& _State, _Byte* _First2, _Byte* _Last2,
        _Byte*& _Mid2) const { // generate bytes to return to default shift state
        return do_unshift(_State, _First2, _Last2, _Mid2);
    }

    int __CLR_OR_THIS_CALL length(_Statype& _State, const _Byte* _First1, const _Byte* _Last1,
        size_t _Count) const { // return min(_Count, converted length of bytes [_First1, _Last1))
        return do_length(_State, _First1, _Last1, _Count);
    }

    __PURE_APPDOMAIN_GLOBAL static locale::id id;

    explicit __CLR_OR_THIS_CALL codecvt(size_t _Refs = 0)
        : codecvt_base(_Refs), _Maxcode(0x10ffff), _Mode(_Consume_header) { // construct from current locale
        _BEGIN_LOCINFO(_Lobj)
        _Init(_Lobj);
        _END_LOCINFO()
    }

    __CLR_OR_THIS_CALL codecvt(const _Locinfo& _Lobj, size_t _Refs = 0)
        : codecvt_base(_Refs), _Maxcode(0x10ffff), _Mode(_Consume_header) { // construct from specified locale
        _Init(_Lobj);
    }

    __CLR_OR_THIS_CALL codecvt(
        const _Locinfo& _Lobj, unsigned long _Maxcode_arg, _Codecvt_mode _Mode_arg, size_t _Refs = 0)
        : codecvt_base(_Refs), _Maxcode(_Maxcode_arg),
          _Mode(_Mode_arg) { // construct from specified locale and parameters
        _Init(_Lobj);
    }

    static size_t __CLRCALL_OR_CDECL _Getcat(const locale::facet** _Ppf = nullptr,
        const locale* _Ploc = nullptr) { // return locale category mask and construct standard facet
        if (_Ppf != nullptr && *_Ppf == nullptr) {
            *_Ppf = new codecvt<_Elem, _Byte, _Statype>(_Locinfo(_Ploc->c_str()));
        }

        return _X_CTYPE;
    }

protected:
    virtual __CLR_OR_THIS_CALL ~codecvt() noexcept { // destroy the object
    }

    void __CLR_OR_THIS_CALL _Init(const _Locinfo&) { // initialize
    }

    virtual result __CLR_OR_THIS_CALL do_in(_Statype& _State, const _Byte* _First1, const _Byte* _Last1,
        const _Byte*& _Mid1, _Elem* _First2, _Elem* _Last2,
        _Elem*& _Mid2) const { // convert bytes [_First1, _Last1) to [_First2, _Last2)
        unsigned short* _Pstate = (unsigned short*) &_State;
        _Mid1                   = _First1;
        _Mid2                   = _First2;

        while (_Mid1 != _Last1 && _Mid2 != _Last2) { // convert a multibyte sequence
            unsigned char _By = (unsigned char) *_Mid1;
            unsigned long _Ch;
            int _Nextra, _Nskip;

            if (*_Pstate > 1) {
                if (_By < 0x80 || 0xc0 <= _By) {
                    return _Mybase::error; // not continuation byte
                }

                // deliver second half of two-word value
                ++_Mid1;
                *_Mid2++ = (_Elem)(*_Pstate | (_By & 0x3f));
                *_Pstate = 1;
                continue;
            }

            if (_By < 0x80) {
                _Ch     = _By;
                _Nextra = 0;
            } else if (_By < 0xc0) { // 0x80-0xdf not first byte
                ++_Mid1;
                return _Mybase::error;
            } else if (_By < 0xe0) {
                _Ch     = static_cast<unsigned long>(_By & 0x1f);
                _Nextra = 1;
            } else if (_By < 0xf0) {
                _Ch     = static_cast<unsigned long>(_By & 0x0f);
                _Nextra = 2;
            } else if (_By < 0xf8) {
                _Ch     = static_cast<unsigned long>(_By & 0x07);
                _Nextra = 3;
            } else {
                _Ch     = static_cast<unsigned long>(_By & 0x03);
                _Nextra = _By < 0xfc ? 4 : 5;
            }

            _Nskip  = _Nextra < 3 ? 0 : 1; // leave a byte for 2nd word
            _First1 = _Mid1; // roll back point

            if (_Nextra == 0) {
                ++_Mid1;
            } else if (_Last1 - _Mid1 < _Nextra + 1 - _Nskip) {
                break; // not enough input
            } else {
                for (++_Mid1; _Nskip < _Nextra; --_Nextra, ++_Mid1) {
                    if ((_By = (unsigned char) *_Mid1) < 0x80 || 0xc0 <= _By) {
                        return _Mybase::error; // not continuation byte
                    } else {
                        _Ch = _Ch << 6 | (_By & 0x3f);
                    }
                }
            }

            if (0 < _Nskip) {
                _Ch <<= 6; // get last byte on next call
            }

            if ((_Maxcode < 0x10ffff ? _Maxcode : 0x10ffff) < _Ch) {
                return _Mybase::error; // value too large
            }

            if (0xffff < _Ch) { // deliver first half of two-word value, save second word
                unsigned short _Ch0 = (unsigned short) (0xd800 | (_Ch >> 10) - 0x0040);

                *_Mid2++ = (_Elem) _Ch0;
                *_Pstate = (unsigned short) (0xdc00 | (_Ch & 0x03ff));
                continue;
            }

            if (_Nskip != 0) {
                if (_Mid1 == _Last1) { // not enough bytes, noncanonical value
                    _Mid1 = _First1;
                    break;
                }

                if ((_By = (unsigned char) *_Mid1++) < 0x80 || 0xc0 <= _By) {
                    return _Mybase::error; // not continuation byte
                }

                _Ch |= _By & 0x3f; // complete noncanonical value
            }

            if (*_Pstate == 0) { // first time, maybe look for and consume header
                *_Pstate = 1;

                if ((_Mode & _Consume_header) != 0 && _Ch == 0xfeff) { // drop header and retry
                    const result _Ans = do_in(_State, _Mid1, _Last1, _Mid1, _First2, _Last2, _Mid2);

                    if (_Ans == _Mybase::partial) { // roll back header determination
                        *_Pstate = 0;
                        _Mid1    = _First1;
                    }

                    return _Ans;
                }
            }

            *_Mid2++ = (_Elem) _Ch;
        }

        return _First1 == _Mid1 ? _Mybase::partial : _Mybase::ok;
    }

    virtual result __CLR_OR_THIS_CALL do_out(_Statype& _State, const _Elem* _First1, const _Elem* _Last1,
        const _Elem*& _Mid1, _Byte* _First2, _Byte* _Last2,
        _Byte*& _Mid2) const { // convert [_First1, _Last1) to bytes [_First2, _Last)
        unsigned short* _Pstate = (unsigned short*) &_State;
        _Mid1                   = _First1;
        _Mid2                   = _First2;

        while (_Mid1 != _Last1 && _Mid2 != _Last2) { // convert and put a wide char
            unsigned long _Ch;
            const unsigned short _Ch1 = (unsigned short) *_Mid1;
            bool _Save                = false;

            if (1 < *_Pstate) { // get saved MS 11 bits from *_Pstate
                if (_Ch1 < 0xdc00 || 0xe000 <= _Ch1) {
                    return _Mybase::error; // bad second word
                }

                _Ch = static_cast<unsigned long>((*_Pstate << 10) | (_Ch1 - 0xdc00));
            } else if (0xd800 <= _Ch1 && _Ch1 < 0xdc00) { // get new first word
                _Ch   = static_cast<unsigned long>((_Ch1 - 0xd800 + 0x0040) << 10);
                _Save = true; // put only first byte, rest with second word
            } else {
                _Ch = _Ch1; // not first word, just put it
            }

            _Byte _By;
            int _Nextra;

            if (_Ch < 0x0080) {
                _By     = (_Byte) _Ch;
                _Nextra = 0;
            } else if (_Ch < 0x0800) {
                _By     = (_Byte)(0xc0 | _Ch >> 6);
                _Nextra = 1;
            } else if (_Ch < 0x10000) {
                _By     = (_Byte)(0xe0 | _Ch >> 12);
                _Nextra = 2;
            } else {
                _By     = (_Byte)(0xf0 | _Ch >> 18);
                _Nextra = 3;
            }

            int _Nput = _Nextra < 3 ? _Nextra + 1 : _Save ? 1 : 3;

            if (_Last2 - _Mid2 < _Nput) {
                break; // not enough room, even without header
            }

            if (*_Pstate == 0 && (_Mode & _Generate_header) != 0) {
                if (_Last2 - _Mid2 < 3 + _Nput) {
                    break; // not enough room for header + output
                }

                // prepend header
                *_Mid2++ = (_Byte)(unsigned char) 0xef;
                *_Mid2++ = (_Byte)(unsigned char) 0xbb;
                *_Mid2++ = (_Byte)(unsigned char) 0xbf;
            }

            ++_Mid1;
            if (_Save || _Nextra < 3) { // put first byte of sequence, if not already put
                *_Mid2++ = _By;
                --_Nput;
            }

            for (; 0 < _Nput; --_Nput) {
                *_Mid2++ = (_Byte)((_Ch >> 6 * --_Nextra & 0x3f) | 0x80);
            }

            *_Pstate = (unsigned short) (_Save ? _Ch >> 10 : 1);
        }

        return _First1 == _Mid1 ? _Mybase::partial : _Mybase::ok;
    }

    virtual result __CLR_OR_THIS_CALL do_unshift(_Statype& _State, _Byte* _First2, _Byte*,
        _Byte*& _Mid2) const { // generate bytes to return to default shift state
        unsigned short* _Pstate = (unsigned short*) &_State;
        _Mid2                   = _First2;

        return 1 < *_Pstate ? _Mybase::error : _Mybase::ok; // fail if trailing first word
    }

    virtual int __CLR_OR_THIS_CALL do_length(_Statype& _State, const _Byte* _First1, const _Byte* _Last1,
        size_t _Count) const { // return min(_Count, converted length of bytes [_First1, _Last1))
        size_t _Wchars    = 0;
        _Statype _Mystate = _State;

        while (_Wchars < _Count && _First1 != _Last1) { // convert another wide character
            const _Byte* _Mid1;
            _Elem* _Mid2;
            _Elem _Ch;
            const auto _Result = do_in(_Mystate, _First1, _Last1, _Mid1, &_Ch, &_Ch + 1, _Mid2);
            if (_Result == _Mybase::noconv) {
                _Wchars += static_cast<size_t>(_Last1 - _First1);
                break;
            }

            if (_Result == _Mybase::ok) {
                if (_Mid2 == &_Ch + 1) {
                    ++_Wchars; // replacement do_in might not convert one
                }

                _First1 = _Mid1;
                continue;
            }

            break; // error or partial
        }

        return static_cast<int>(_Min_value(static_cast<size_t>(INT_MAX), _Wchars));
    }

    virtual bool __CLR_OR_THIS_CALL do_always_noconv() const
        noexcept override { // return true if conversions never change input
        return false;
    }

    virtual int __CLR_OR_THIS_CALL do_max_length() const
        noexcept override { // return maximum length required for a conversion
        return (_Mode & _Consume_header) != 0
                   ? 9 // header + max input
                   : (_Mode & _Generate_header) != 0 ? 7 // header + max output
                                                     : 6; // 6-byte max input sequence, no 3-byte header
    }

    virtual int do_encoding() const noexcept override { // return length of code sequence (from codecvt)
        return 0; // 0 => varying length
    }

private:
    unsigned long _Maxcode; // default: 0x10ffff
    _Codecvt_mode _Mode; // default: _Consume_header
};

// CLASS codecvt<char32_t, char, _Mbstatet>
template <>
class _CRTIMP2_PURE_IMPORT codecvt<char32_t, char, _Mbstatet>
    : public codecvt_base { // facet for converting between char32_t and UTF-8 byte sequences
public:
    using _Mybase     = codecvt<char32_t, char, _Mbstatet>;
    using _Elem       = char32_t;
    using _Byte       = char;
    using _Statype    = _Mbstatet;
    using intern_type = _Elem;
    using extern_type = _Byte;
    using state_type  = _Statype;

    result __CLR_OR_THIS_CALL in(_Statype& _State, const _Byte* _First1, const _Byte* _Last1, const _Byte*& _Mid1,
        _Elem* _First2, _Elem* _Last2, _Elem*& _Mid2) const { // convert bytes [_First1, _Last1) to [_First2, _Last)
        return do_in(_State, _First1, _Last1, _Mid1, _First2, _Last2, _Mid2);
    }

    result __CLR_OR_THIS_CALL out(_Statype& _State, const _Elem* _First1, const _Elem* _Last1, const _Elem*& _Mid1,
        _Byte* _First2, _Byte* _Last2, _Byte*& _Mid2) const { // convert [_First1, _Last1) to bytes [_First2, _Last)
        return do_out(_State, _First1, _Last1, _Mid1, _First2, _Last2, _Mid2);
    }

    result __CLR_OR_THIS_CALL unshift(_Statype& _State, _Byte* _First2, _Byte* _Last2,
        _Byte*& _Mid2) const { // generate bytes to return to default shift state
        return do_unshift(_State, _First2, _Last2, _Mid2);
    }

    int __CLR_OR_THIS_CALL length(_Statype& _State, const _Byte* _First1, const _Byte* _Last1,
        size_t _Count) const { // return min(_Count, converted length of bytes [_First1, _Last1))
        return do_length(_State, _First1, _Last1, _Count);
    }

    __PURE_APPDOMAIN_GLOBAL static locale::id id;

    explicit __CLR_OR_THIS_CALL codecvt(size_t _Refs = 0)
        : codecvt_base(_Refs), _Maxcode(0xffffffff), _Mode(_Consume_header) { // construct from current locale
        _BEGIN_LOCINFO(_Lobj)
        _Init(_Lobj);
        _END_LOCINFO()
    }

    __CLR_OR_THIS_CALL codecvt(const _Locinfo& _Lobj, size_t _Refs = 0)
        : codecvt_base(_Refs), _Maxcode(0xffffffff), _Mode(_Consume_header) { // construct from specified locale
        _Init(_Lobj);
    }

    __CLR_OR_THIS_CALL codecvt(
        const _Locinfo& _Lobj, unsigned long _Maxcode_arg, _Codecvt_mode _Mode_arg, size_t _Refs = 0)
        : codecvt_base(_Refs), _Maxcode(_Maxcode_arg),
          _Mode(_Mode_arg) { // construct from specified locale and parameters
        _Init(_Lobj);
    }

    static size_t __CLRCALL_OR_CDECL _Getcat(const locale::facet** _Ppf = nullptr,
        const locale* _Ploc = nullptr) { // return locale category mask and construct standard facet
        if (_Ppf != nullptr && *_Ppf == nullptr) {
            *_Ppf = new codecvt<_Elem, _Byte, _Statype>(_Locinfo(_Ploc->c_str()));
        }

        return _X_CTYPE;
    }

protected:
    virtual __CLR_OR_THIS_CALL ~codecvt() noexcept { // destroy the object
    }

    void __CLR_OR_THIS_CALL _Init(const _Locinfo&) { // initialize
    }

    virtual result __CLR_OR_THIS_CALL do_in(_Statype& _State, const _Byte* _First1, const _Byte* _Last1,
        const _Byte*& _Mid1, _Elem* _First2, _Elem* _Last2,
        _Elem*& _Mid2) const { // convert bytes [_First1, _Last1) to [_First2, _Last)
        char* _Pstate = (char*) &_State;
        _Mid1         = _First1;
        _Mid2         = _First2;

        while (_Mid1 != _Last1 && _Mid2 != _Last2) { // convert a multibyte sequence
            unsigned char _By = (unsigned char) *_Mid1;
            unsigned long _Ch;
            int _Nextra;

            if (_By < 0x80) {
                _Ch     = _By;
                _Nextra = 0;
            } else if (_By < 0xc0) { // 0x80-0xdf not first byte
                ++_Mid1;
                return _Mybase::error;
            } else if (_By < 0xe0) {
                _Ch     = static_cast<unsigned long>(_By & 0x1f);
                _Nextra = 1;
            } else if (_By < 0xf0) {
                _Ch     = static_cast<unsigned long>(_By & 0x0f);
                _Nextra = 2;
            } else if (_By < 0xf8) {
                _Ch     = static_cast<unsigned long>(_By & 0x07);
                _Nextra = 3;
            } else {
                _Ch     = static_cast<unsigned long>(_By & 0x03);
                _Nextra = _By < 0xfc ? 4 : 5;
            }

            if (_Nextra == 0) {
                ++_Mid1;
            } else if (_Last1 - _Mid1 < _Nextra + 1) {
                break; // not enough input
            } else {
                for (++_Mid1; 0 < _Nextra; --_Nextra, ++_Mid1) {
                    if ((_By = (unsigned char) *_Mid1) < 0x80 || 0xc0 <= _By) {
                        return _Mybase::error; // not continuation byte
                    } else {
                        _Ch = _Ch << 6 | (_By & 0x3f);
                    }
                }
            }

            if (*_Pstate == 0) { // first time, maybe look for and consume header
                *_Pstate = 1;

                if ((_Mode & _Consume_header) != 0 && _Ch == 0xfeff) { // drop header and retry
                    const result _Ans = do_in(_State, _Mid1, _Last1, _Mid1, _First2, _Last2, _Mid2);

                    if (_Ans == _Mybase::partial) { // roll back header determination
                        *_Pstate = 0;
                        _Mid1    = _First1;
                    }
                    return _Ans;
                }
            }

            if (_Maxcode < _Ch) {
                return _Mybase::error; // code too large
            }

            *_Mid2++ = (_Elem) _Ch;
        }

        return _First1 == _Mid1 ? _Mybase::partial : _Mybase::ok;
    }

    virtual result __CLR_OR_THIS_CALL do_out(_Statype& _State, const _Elem* _First1, const _Elem* _Last1,
        const _Elem*& _Mid1, _Byte* _First2, _Byte* _Last2,
        _Byte*& _Mid2) const { // convert [_First1, _Last1) to bytes [_First2, _Last)
        char* _Pstate = (char*) &_State;
        _Mid1         = _First1;
        _Mid2         = _First2;

        while (_Mid1 != _Last1 && _Mid2 != _Last2) { // convert and put a wide char
            _Byte _By;
            int _Nextra;
            unsigned long _Ch = (unsigned long) *_Mid1;

            if (_Maxcode < _Ch) {
                return _Mybase::error;
            }

            if (_Ch < 0x0080) {
                _By     = (_Byte) _Ch;
                _Nextra = 0;
            } else if (_Ch < 0x0800) {
                _By     = (_Byte)(0xc0 | _Ch >> 6);
                _Nextra = 1;
            } else if (_Ch < 0x00010000) {
                _By     = (_Byte)(0xe0 | _Ch >> 12);
                _Nextra = 2;
            } else if (_Ch < 0x00200000) {
                _By     = (_Byte)(0xf0 | _Ch >> 18);
                _Nextra = 3;
            } else if (_Ch < 0x04000000) {
                _By     = (_Byte)(0xf8 | _Ch >> 24);
                _Nextra = 4;
            } else {
                _By     = (_Byte)(0xfc | (_Ch >> 30 & 0x03));
                _Nextra = 5;
            }

            if (*_Pstate == 0) { // first time, maybe generate header
                *_Pstate = 1;
                if ((_Mode & _Generate_header) != 0) {
                    if (_Last2 - _Mid2 < 3 + 1 + _Nextra) {
                        return _Mybase::partial; // not enough room for both
                    }

                    // prepend header
                    *_Mid2++ = (_Byte)(unsigned char) 0xef;
                    *_Mid2++ = (_Byte)(unsigned char) 0xbb;
                    *_Mid2++ = (_Byte)(unsigned char) 0xbf;
                }
            }

            if (_Last2 - _Mid2 < 1 + _Nextra) {
                break; // not enough room for output
            }

            ++_Mid1;
            for (*_Mid2++ = _By; 0 < _Nextra;) {
                *_Mid2++ = (_Byte)((_Ch >> 6 * --_Nextra & 0x3f) | 0x80);
            }
        }
        return _First1 == _Mid1 ? _Mybase::partial : _Mybase::ok;
    }

    virtual result __CLR_OR_THIS_CALL do_unshift(
        _Statype&, _Byte* _First2, _Byte*, _Byte*& _Mid2) const { // generate bytes to return to default shift state
        _Mid2 = _First2;

        return _Mybase::noconv;
    }

    virtual int __CLR_OR_THIS_CALL do_length(_Statype& _State, const _Byte* _First1, const _Byte* _Last1,
        size_t _Count) const { // return min(_Count, converted length of bytes [_First1, _Last1))
        size_t _Wchars    = 0;
        _Statype _Mystate = _State;

        while (_Wchars < _Count && _First1 != _Last1) { // convert another wide character
            const _Byte* _Mid1;
            _Elem* _Mid2;
            _Elem _Ch;
            const auto _Result = do_in(_Mystate, _First1, _Last1, _Mid1, &_Ch, &_Ch + 1, _Mid2);
            if (_Result == _Mybase::noconv) {
                _Wchars += static_cast<size_t>(_Last1 - _First1);
                break;
            }

            if (_Result == _Mybase::ok) {
                if (_Mid2 == &_Ch + 1) {
                    ++_Wchars; // replacement do_in might not convert one
                }

                _First1 = _Mid1;
                continue;
            }

            break; // error or partial
        }

        return static_cast<int>(_Min_value(static_cast<size_t>(INT_MAX), _Wchars));
    }

    virtual bool __CLR_OR_THIS_CALL do_always_noconv() const
        noexcept override { // return true if conversions never change input
        return false;
    }

    virtual int __CLR_OR_THIS_CALL do_max_length() const
        noexcept override { // return maximum length required for a conversion
        return (_Mode & (_Consume_header | _Generate_header)) != 0 ? 9 : 6;
    }

    virtual int __CLR_OR_THIS_CALL do_encoding() const
        noexcept override { // return length of code sequence (from codecvt)
        return (_Mode & (_Consume_header | _Generate_header)) != 0 ? -1
                                                                   : 0; // -1 => state dependent, 0 => varying length
    }

private:
    unsigned long _Maxcode; // default: 0xffffffff
    _Codecvt_mode _Mode; // default: _Consume_header
};

// CLASS codecvt<wchar_t, char, _Mbstatet>
template <>
class _CRTIMP2_PURE_IMPORT codecvt<wchar_t, char, _Mbstatet>
    : public codecvt_base { // facet for converting between wchar_t and char (_Byte) sequences
public:
    using _Elem       = wchar_t;
    using _Byte       = char;
    using _Statype    = _Mbstatet;
    using intern_type = _Elem;
    using extern_type = _Byte;
    using state_type  = _Statype;

    result __CLR_OR_THIS_CALL in(_Statype& _State, const _Byte* _First1, const _Byte* _Last1, const _Byte*& _Mid1,
        _Elem* _First2, _Elem* _Last2, _Elem*& _Mid2) const { // convert bytes [_First1, _Last1) to [_First2, _Last)
        return do_in(_State, _First1, _Last1, _Mid1, _First2, _Last2, _Mid2);
    }

    result __CLR_OR_THIS_CALL out(_Statype& _State, const _Elem* _First1, const _Elem* _Last1, const _Elem*& _Mid1,
        _Byte* _First2, _Byte* _Last2, _Byte*& _Mid2) const { // convert [_First1, _Last1) to bytes [_First2, _Last)
        return do_out(_State, _First1, _Last1, _Mid1, _First2, _Last2, _Mid2);
    }

    result __CLR_OR_THIS_CALL unshift(_Statype& _State, _Byte* _First2, _Byte* _Last2,
        _Byte*& _Mid2) const { // generate bytes to return to default shift state
        return do_unshift(_State, _First2, _Last2, _Mid2);
    }

    int __CLR_OR_THIS_CALL length(_Statype& _State, const _Byte* _First1, const _Byte* _Last1,
        size_t _Count) const { // return min(_Count, converted length of bytes [_First1, _Last1))
        return do_length(_State, _First1, _Last1, _Count);
    }

    __PURE_APPDOMAIN_GLOBAL static locale::id id;

    explicit __CLR_OR_THIS_CALL codecvt(size_t _Refs = 0) : codecvt_base(_Refs) { // construct from current locale
        _BEGIN_LOCINFO(_Lobj)
        _Init(_Lobj);
        _END_LOCINFO()
    }

    __CLR_OR_THIS_CALL codecvt(const _Locinfo& _Lobj, size_t _Refs = 0)
        : codecvt_base(_Refs) { // construct from specified locale
        _Init(_Lobj);
    }

    static size_t __CLRCALL_OR_CDECL _Getcat(const locale::facet** _Ppf = nullptr,
        const locale* _Ploc = nullptr) { // return locale category mask and construct standard facet
        if (_Ppf != nullptr && *_Ppf == nullptr) {
            *_Ppf = new codecvt<_Elem, _Byte, _Statype>(_Locinfo(_Ploc->c_str()));
        }

        return _X_CTYPE;
    }

protected:
    virtual __CLR_OR_THIS_CALL ~codecvt() noexcept { // destroy the object
    }

    void __CLR_OR_THIS_CALL _Init(const _Locinfo& _Lobj) { // initialize from _Lobj
        _Cvt = _Lobj._Getcvt();
    }

    virtual result __CLR_OR_THIS_CALL do_in(_Statype&, const _Byte* _First1, const _Byte* _Last1, const _Byte*& _Mid1,
        _Elem* _First2, _Elem* _Last2, _Elem*& _Mid2) const { // convert bytes [_First1, _Last1) to [_First2, _Last)
        _Statype _Mystate{};
        _Adl_verify_range(_First1, _Last1);
        _Adl_verify_range(_First2, _Last2);
        _Mid1 = _First1;
        _Mid2 = _First2;
        for (;;) {
            if (_Mid1 == _Last1) {
                return ok;
            }

            if (_Mid2 == _Last2) {
                return partial;
            }

            int _Bytes = _Mbrtowc(_Mid2, _Mid1, static_cast<size_t>(_Last1 - _Mid1), &_Mystate, &_Cvt);
            switch (_Bytes) {
            case -2: // partial conversion
                return partial;

            case -1: // failed conversion
                return error;

            case 0: // converted NULL character, TRANSITION, VSO#654347
                _Bytes = 1;
                // [[fallthrough]];

            default: // converted some other character
                _Mid1 += _Bytes;
                ++_Mid2;
                break;
            }
        }
    }

    virtual result __CLR_OR_THIS_CALL do_out(_Statype& _State, const _Elem* _First1, const _Elem* _Last1,
        const _Elem*& _Mid1, _Byte* _First2, _Byte* _Last2,
        _Byte*& _Mid2) const { // convert [_First1, _Last1) to bytes [_First2, _Last)
        _Adl_verify_range(_First1, _Last1);
        _Adl_verify_range(_First2, _Last2);
        _Mid1 = _First1;
        _Mid2 = _First2;
        int _Bytes;

        while (_Mid1 != _Last1 && _Mid2 != _Last2) {
            if ((int) MB_LEN_MAX <= _Last2 - _Mid2) {
                if ((_Bytes = _Wcrtomb(_Mid2, *_Mid1, &_State, &_Cvt)) < 0) {
                    return error; // locale-specific wcrtomb failed
                } else {
                    ++_Mid1;
                    _Mid2 += _Bytes;
                }
            } else { // destination too small, convert into buffer
                _Byte _Buf[MB_LEN_MAX];
                _Statype _Stsave = _State;

                if ((_Bytes = _Wcrtomb(_Buf, *_Mid1, &_State, &_Cvt)) < 0) {
                    return error; // locale-specific wcrtomb failed
                } else if (_Last2 - _Mid2 < _Bytes) { // converted too many, roll back and return previous
                    _State = _Stsave;
                    break;
                } else { // copy converted bytes from buffer
                    _CSTD memcpy(_Mid2, _Buf, static_cast<size_t>(_Bytes));
                    ++_Mid1;
                    _Mid2 += _Bytes;
                }
            }
        }

        return _Mid1 == _Last1 ? ok : partial;
    }

    virtual result __CLR_OR_THIS_CALL do_unshift(_Statype& _State, _Byte* _First2, _Byte* _Last2,
        _Byte*& _Mid2) const { // generate bytes to return to default shift state
        _Adl_verify_range(_First2, _Last2);
        _Mid2       = _First2;
        result _Ans = ok;
        int _Bytes;
        _Byte _Buf[MB_LEN_MAX];
        _Statype _Stsave = _State;

        if ((_Bytes = _Wcrtomb(_Buf, L'\0', &_State, &_Cvt)) <= 0) {
            _Ans = error; // locale-specific wcrtomb failed
        } else if (_Last2 - _Mid2 < --_Bytes) { // converted too many, roll back and return
            _State = _Stsave;
            _Ans   = partial;
        } else if (0 < _Bytes) { // copy converted bytes from buffer
            _CSTD memcpy(_Mid2, _Buf, static_cast<size_t>(_Bytes));
            _Mid2 += _Bytes;
        }
        return _Ans;
    }

    virtual int __CLR_OR_THIS_CALL do_length(_Statype&, const _Byte* _First1, const _Byte* _Last1,
        size_t _Count) const { // return min(_Count, converted length of bytes [_First1, _Last1))
        _Adl_verify_range(_First1, _Last1);
        size_t _Wchars = 0;
        _Statype _Mystate{};

        while (_Wchars < _Count && _First1 != _Last1) {
            _Elem _Ch;
            int _Bytes = _Mbrtowc(&_Ch, _First1, static_cast<size_t>(_Last1 - _First1), &_Mystate, &_Cvt);
            if (_Bytes < 0) { // partial or failed conversion
                break;
            }

            if (_Bytes == 0) { // converted NULL character, TRANSITION, VSO#654347
                _Bytes = 1;
            }

            // converted _Bytes bytes to a wchar_t:
            _First1 += _Bytes;
            ++_Wchars;
        }

        return static_cast<int>(_Min_value(static_cast<size_t>(INT_MAX), _Wchars));
    }

    virtual bool __CLR_OR_THIS_CALL do_always_noconv() const
        noexcept override { // return true if conversions never change input
        return false;
    }

    virtual int __CLR_OR_THIS_CALL do_max_length() const
        noexcept override { // return maximum length required for a conversion (from codecvt)
        return static_cast<int>(_Cvt._Mbcurmax);
    }

    virtual int __CLR_OR_THIS_CALL do_encoding() const
        noexcept override { // return length of code sequence (from codecvt)
        return _Cvt._Mbcurmax == 1; // 0 => varying length, 1 => fixed length
    }

private:
    _Locinfo::_Cvtvec _Cvt; // locale info passed to _Mbrtowc, _Wcrtomb
};

#ifdef _NATIVE_WCHAR_T_DEFINED
// CLASS codecvt<unsigned short, char, _Mbstatet>
template <>
class _CRTIMP2_PURE_IMPORT codecvt<unsigned short, char, _Mbstatet>
    : public codecvt_base { // facet for converting between unsigned short and char sequences
public:
    using _Elem       = unsigned short;
    using _Byte       = char;
    using _Statype    = _Mbstatet;
    using intern_type = _Elem;
    using extern_type = _Byte;
    using state_type  = _Statype;

    result __CLR_OR_THIS_CALL in(_Statype& _State, const _Byte* _First1, const _Byte* _Last1, const _Byte*& _Mid1,
        _Elem* _First2, _Elem* _Last2, _Elem*& _Mid2) const { // convert bytes [_First1, _Last1) to [_First2, _Last)
        return do_in(_State, _First1, _Last1, _Mid1, _First2, _Last2, _Mid2);
    }

    result __CLR_OR_THIS_CALL out(_Statype& _State, const _Elem* _First1, const _Elem* _Last1, const _Elem*& _Mid1,
        _Byte* _First2, _Byte* _Last2, _Byte*& _Mid2) const { // convert [_First1, _Last1) to bytes [_First2, _Last)
        return do_out(_State, _First1, _Last1, _Mid1, _First2, _Last2, _Mid2);
    }

    result __CLR_OR_THIS_CALL unshift(_Statype& _State, _Byte* _First2, _Byte* _Last2,
        _Byte*& _Mid2) const { // generate bytes to return to default shift state
        return do_unshift(_State, _First2, _Last2, _Mid2);
    }

    int __CLR_OR_THIS_CALL length(_Statype& _State, const _Byte* _First1, const _Byte* _Last1,
        size_t _Count) const { // return min(_Count, converted length of bytes [_First1, _Last1))
        return do_length(_State, _First1, _Last1, _Count);
    }

    __PURE_APPDOMAIN_GLOBAL static locale::id id;

    explicit __CLR_OR_THIS_CALL codecvt(size_t _Refs = 0) : codecvt_base(_Refs) { // construct from current locale
        _BEGIN_LOCINFO(_Lobj)
        _Init(_Lobj);
        _END_LOCINFO()
    }

    __CLR_OR_THIS_CALL codecvt(const _Locinfo& _Lobj, size_t _Refs = 0)
        : codecvt_base(_Refs) { // construct from specified locale
        _Init(_Lobj);
    }

    static size_t __CLRCALL_OR_CDECL _Getcat(const locale::facet** _Ppf = nullptr,
        const locale* _Ploc = nullptr) { // return locale category mask and construct standard facet
        if (_Ppf != nullptr && *_Ppf == nullptr) {
            *_Ppf = new codecvt<_Elem, _Byte, _Statype>(_Locinfo(_Ploc->c_str()));
        }

        return _X_CTYPE;
    }

protected:
    virtual __CLR_OR_THIS_CALL ~codecvt() noexcept { // destroy the object
    }

    void __CLR_OR_THIS_CALL _Init(const _Locinfo& _Lobj) { // initialize from _Lobj
        _Cvt = _Lobj._Getcvt();
    }

    virtual result __CLR_OR_THIS_CALL do_in(_Statype&, const _Byte* _First1, const _Byte* _Last1, const _Byte*& _Mid1,
        _Elem* _First2, _Elem* _Last2, _Elem*& _Mid2) const { // convert bytes [_First1, _Last1) to [_First2, _Last)
        _Statype _Mystate{};
        _Adl_verify_range(_First1, _Last1);
        _Adl_verify_range(_First2, _Last2);
        _Mid1 = _First1;
        _Mid2 = _First2;
        for (;;) {
            if (_Mid1 == _Last1) {
                return ok;
            }

            if (_Mid2 == _Last2) {
                return partial;
            }

            int _Bytes = _Mbrtowc(
                reinterpret_cast<wchar_t*>(_Mid2), _Mid1, static_cast<size_t>(_Last1 - _Mid1), &_Mystate, &_Cvt);
            switch (_Bytes) {
            case -2: // partial conversion
                return partial;

            case -1: // failed conversion
                return error;

            case 0: // converted NULL character, TRANSITION, VSO#654347
                _Bytes = 1;
                // [[fallthrough]];

            default: // converted some other character
                _Mid1 += _Bytes;
                ++_Mid2;
                break;
            }
        }
    }

    virtual result __CLR_OR_THIS_CALL do_out(_Statype& _State, const _Elem* _First1, const _Elem* _Last1,
        const _Elem*& _Mid1, _Byte* _First2, _Byte* _Last2,
        _Byte*& _Mid2) const { // convert [_First1, _Last1) to bytes [_First2, _Last)
        _Adl_verify_range(_First1, _Last1);
        _Adl_verify_range(_First2, _Last2);
        _Mid1 = _First1;
        _Mid2 = _First2;
        int _Bytes;

        while (_Mid1 != _Last1 && _Mid2 != _Last2) {
            if ((int) MB_LEN_MAX <= _Last2 - _Mid2) {
                if ((_Bytes = _Wcrtomb(_Mid2, *_Mid1, &_State, &_Cvt)) < 0) {
                    return error; // locale-specific wcrtomb failed
                } else {
                    ++_Mid1;
                    _Mid2 += _Bytes;
                }
            } else { // destination too small, convert into buffer
                _Byte _Buf[MB_LEN_MAX];
                _Statype _Stsave = _State;

                if ((_Bytes = _Wcrtomb(_Buf, *_Mid1, &_State, &_Cvt)) < 0) {
                    return error; // locale-specific wcrtomb failed
                } else if (_Last2 - _Mid2 < _Bytes) { // converted too many, roll back and return previous
                    _State = _Stsave;
                    break;
                } else { // copy converted bytes from buffer
                    _CSTD memcpy(_Mid2, _Buf, static_cast<size_t>(_Bytes));
                    ++_Mid1;
                    _Mid2 += _Bytes;
                }
            }
        }

        return _Mid1 == _Last1 ? ok : partial;
    }

    virtual result __CLR_OR_THIS_CALL do_unshift(_Statype& _State, _Byte* _First2, _Byte* _Last2,
        _Byte*& _Mid2) const { // generate bytes to return to default shift state
        _Adl_verify_range(_First2, _Last2);
        _Mid2       = _First2;
        result _Ans = ok;
        int _Bytes;
        _Byte _Buf[MB_LEN_MAX];
        _Statype _Stsave = _State;

        if ((_Bytes = _Wcrtomb(_Buf, L'\0', &_State, &_Cvt)) <= 0) {
            _Ans = error; // locale-specific wcrtomb failed
        } else if (_Last2 - _Mid2 < --_Bytes) { // converted too many, roll back and return
            _State = _Stsave;
            _Ans   = partial;
        } else if (0 < _Bytes) { // copy converted bytes from buffer
            _CSTD memcpy(_Mid2, _Buf, static_cast<size_t>(_Bytes));
            _Mid2 += _Bytes;
        }

        return _Ans;
    }

    virtual int __CLR_OR_THIS_CALL do_length(_Statype&, const _Byte* _First1, const _Byte* _Last1,
        size_t _Count) const { // return min(_Count, converted length of bytes [_First1, _Last1))
        _Adl_verify_range(_First1, _Last1);
        size_t _Wchars = 0;
        _Statype _Mystate{};

        while (_Wchars < _Count && _First1 != _Last1) {
            wchar_t _Ch;
            int _Bytes = _Mbrtowc(&_Ch, _First1, static_cast<size_t>(_Last1 - _First1), &_Mystate, &_Cvt);
            if (_Bytes < 0) { // partial or failed conversion
                break;
            }

            if (_Bytes == 0) { // converted NULL character, TRANSITION, VSO#654347
                _Bytes = 1;
            }

            // converted _Bytes bytes to a wchar_t:
            _First1 += _Bytes;
            ++_Wchars;
        }

        return static_cast<int>(_Min_value(static_cast<size_t>(INT_MAX), _Wchars));
    }

    virtual bool __CLR_OR_THIS_CALL do_always_noconv() const
        noexcept override { // return true if conversions never change input
        return false;
    }

    virtual int __CLR_OR_THIS_CALL do_max_length() const
        noexcept override { // return maximum length required for a conversion (from codecvt)
        return static_cast<int>(_Cvt._Mbcurmax);
    }

    virtual int __CLR_OR_THIS_CALL do_encoding() const
        noexcept override { // return length of code sequence (from codecvt)
        return _Cvt._Mbcurmax == 1; // 0 => varying length, 1 => fixed length
    }

private:
    _Locinfo::_Cvtvec _Cvt; // locale info passed to _Mbrtowc, _Wcrtomb
};
#endif // _NATIVE_WCHAR_T_DEFINED

// CLASS TEMPLATE codecvt_byname
template <class _Elem, class _Byte, class _Statype>
class codecvt_byname : public codecvt<_Elem, _Byte, _Statype> { // codecvt for named locale
public:
    // __cpp_char8_t
    // codecvt_byname<char16_t, char8_t, mbstate_t>
    // codecvt_byname<char32_t, char8_t, mbstate_t>
    static_assert(!_ENFORCE_FACET_SPECIALIZATIONS
                      || _Is_any_of_v<codecvt_byname, //
                             codecvt_byname<char, char, mbstate_t>, //
                             codecvt_byname<wchar_t, char, mbstate_t>>,
        _FACET_SPECIALIZATION_MESSAGE);

    explicit __CLR_OR_THIS_CALL codecvt_byname(const char* _Locname, size_t _Refs = 0)
        : codecvt<_Elem, _Byte, _Statype>(_Locinfo(_Locname), _Refs) { // construct for named locale
    }

    explicit __CLR_OR_THIS_CALL codecvt_byname(const string& _Str, size_t _Refs = 0)
        : codecvt<_Elem, _Byte, _Statype>(_Locinfo(_Str.c_str()), _Refs) { // construct for named locale
    }

protected:
    virtual __CLR_OR_THIS_CALL ~codecvt_byname() noexcept { // destroy the object
    }
};

// STRUCT ctype_base
struct _CRTIMP2_PURE_IMPORT ctype_base : public locale::facet { // base for ctype
    enum { // constants for character classifications
        alnum  = _DI | _LO | _UP | _XA,
        alpha  = _LO | _UP | _XA,
        cntrl  = _BB,
        digit  = _DI,
        graph  = _DI | _LO | _PU | _UP | _XA,
        lower  = _LO,
        print  = _DI | _LO | _PU | _SP | _UP | _XA | _XD,
        punct  = _PU,
        space  = _CN | _SP | _XS,
        upper  = _UP,
        xdigit = _XD,
        blank  = _CN | _SP | _XS | _XB
    };
    using mask = short; // to match <ctype.h>

    __CLR_OR_THIS_CALL ctype_base(size_t _Refs = 0) : locale::facet(_Refs) { // default constructor
    }

    __CLR_OR_THIS_CALL ~ctype_base() noexcept { // destroy the object
    }
};

// CLASS TEMPLATE ctype
template <class _Elem>
class ctype : public ctype_base { // facet for classifying elements, converting cases
public:
    // ctype<char>, ctype<wchar_t>, and ctype<unsigned short> are explicitly specialized below.
    static_assert(!_ENFORCE_FACET_SPECIALIZATIONS || _Always_false<_Elem>, _FACET_SPECIALIZATION_MESSAGE);

    using char_type = _Elem;

    bool __CLR_OR_THIS_CALL is(mask _Maskval, _Elem _Ch) const { // test if element fits any mask classifications
        return do_is(_Maskval, _Ch);
    }

    const _Elem* __CLR_OR_THIS_CALL is(const _Elem* _First, const _Elem* _Last,
        mask* _Dest) const { // get mask sequence for elements in [_First, _Last)
        return do_is(_First, _Last, _Dest);
    }

    const _Elem* __CLR_OR_THIS_CALL scan_is(mask _Maskval, const _Elem* _First,
        const _Elem* _Last) const { // find first in [_First, _Last) that fits mask classification
        return do_scan_is(_Maskval, _First, _Last);
    }

    const _Elem* __CLR_OR_THIS_CALL scan_not(mask _Maskval, const _Elem* _First,
        const _Elem* _Last) const { // find first in [_First, _Last) not fitting mask classification
        return do_scan_not(_Maskval, _First, _Last);
    }

    _Elem __CLR_OR_THIS_CALL tolower(_Elem _Ch) const { // convert element to lower case
        return do_tolower(_Ch);
    }

    const _Elem* __CLR_OR_THIS_CALL tolower(
        _Elem* _First, const _Elem* _Last) const { // convert [_First, _Last) in place to lower case
        return do_tolower(_First, _Last);
    }

    _Elem __CLR_OR_THIS_CALL toupper(_Elem _Ch) const { // convert element to upper case
        return do_toupper(_Ch);
    }

    const _Elem* __CLR_OR_THIS_CALL toupper(
        _Elem* _First, const _Elem* _Last) const { // convert [_First, _Last) in place to upper case
        return do_toupper(_First, _Last);
    }

    _Elem __CLR_OR_THIS_CALL widen(char _Byte) const { // widen char
        return do_widen(_Byte);
    }

    const char* __CLR_OR_THIS_CALL widen(const char* _First, const char* _Last,
        _Elem* _Dest) const { // widen chars in [_First, _Last)
        return do_widen(_First, _Last, _Dest);
    }

    char __CLR_OR_THIS_CALL narrow(_Elem _Ch, char _Dflt = '\0') const { // narrow element to char
        return do_narrow(_Ch, _Dflt);
    }

    const _Elem* __CLR_OR_THIS_CALL narrow(const _Elem* _First, const _Elem* _Last, char _Dflt,
        char* _Dest) const { // narrow elements in [_First, _Last) to chars
        return do_narrow(_First, _Last, _Dflt, _Dest);
    }

    __PURE_APPDOMAIN_GLOBAL static locale::id id;

    explicit __CLR_OR_THIS_CALL ctype(size_t _Refs = 0) : ctype_base(_Refs) { // construct from current locale
        _BEGIN_LOCINFO(_Lobj)
        _Init(_Lobj);
        _END_LOCINFO()
    }

    __CLR_OR_THIS_CALL ctype(const _Locinfo& _Lobj, size_t _Refs = 0)
        : ctype_base(_Refs) { // construct from specified locale
        _Init(_Lobj);
    }

    static size_t __CLRCALL_OR_CDECL _Getcat(const locale::facet** _Ppf = nullptr,
        const locale* _Ploc = nullptr) { // return locale category mask and construct standard facet
        if (_Ppf != nullptr && *_Ppf == nullptr) {
            *_Ppf = new ctype<_Elem>(_Locinfo(_Ploc->c_str()));
        }

        return _X_CTYPE;
    }

protected:
    virtual __CLR_OR_THIS_CALL ~ctype() noexcept { // destroy the object
        if (_Ctype._Delfl) {
            _CSTD free((void*) _Ctype._Table);
        }

        _CSTD free(_Ctype._LocaleName);
    }

    void __CLR_OR_THIS_CALL _Init(const _Locinfo& _Lobj) { // initialize from _Lobj
        _Ctype = _Lobj._Getctype();
        _Cvt   = _Lobj._Getcvt();
    }

    virtual bool __CLR_OR_THIS_CALL do_is(
        mask _Maskval, _Elem _Ch) const { // test if element fits any mask classifications
        return (_Ctype._Table[(unsigned char) narrow(_Ch)] & _Maskval) != 0;
    }

    virtual const _Elem* __CLR_OR_THIS_CALL do_is(const _Elem* _First, const _Elem* _Last,
        mask* _Dest) const { // get mask sequence for elements in [_First, _Last)
        _Adl_verify_range(_First, _Last);
        for (; _First != _Last; ++_First, ++_Dest) {
            *_Dest = _Ctype._Table[(unsigned char) narrow(*_First)];
        }

        return _First;
    }

    virtual const _Elem* __CLR_OR_THIS_CALL do_scan_is(mask _Maskval, const _Elem* _First,
        const _Elem* _Last) const { // find first in [_First, _Last) that fits mask classification
        _Adl_verify_range(_First, _Last);
        while (_First != _Last && !is(_Maskval, *_First)) {
            ++_First;
        }

        return _First;
    }

    virtual const _Elem* __CLR_OR_THIS_CALL do_scan_not(mask _Maskval, const _Elem* _First,
        const _Elem* _Last) const { // find first in [_First, _Last) not fitting mask classification
        _Adl_verify_range(_First, _Last);
        while (_First != _Last && is(_Maskval, *_First)) {
            ++_First;
        }

        return _First;
    }

    virtual _Elem __CLR_OR_THIS_CALL do_tolower(_Elem _Ch) const { // convert element to lower case
        unsigned char _Byte = (unsigned char) narrow(_Ch, '\0');
        if (_Byte == '\0') {
            return _Ch;
        }

        return widen((char) _Tolower(_Byte, &_Ctype));
    }

    virtual const _Elem* __CLR_OR_THIS_CALL do_tolower(_Elem* _First,
        const _Elem* _Last) const { // convert [_First, _Last) in place to lower case
        _Adl_verify_range((const _Elem*) _First, _Last);
        for (; _First != _Last; ++_First) { // convert *_First to lower case
            unsigned char _Byte = (unsigned char) narrow(*_First, '\0');
            if (_Byte != '\0') {
                *_First = (widen((char) _Tolower(_Byte, &_Ctype)));
            }
        }
        return (const _Elem*) _First;
    }

    virtual _Elem __CLR_OR_THIS_CALL do_toupper(_Elem _Ch) const { // convert element to upper case
        unsigned char _Byte = (unsigned char) narrow(_Ch, '\0');
        if (_Byte == '\0') {
            return _Ch;
        }

        return widen((char) _Toupper(_Byte, &_Ctype));
    }

    virtual const _Elem* __CLR_OR_THIS_CALL do_toupper(_Elem* _First,
        const _Elem* _Last) const { // convert [_First, _Last) in place to upper case
        _Adl_verify_range((const _Elem*) _First, _Last);
        for (; _First != _Last; ++_First) { // convert *_First to upper case
            unsigned char _Byte = (unsigned char) narrow(*_First, '\0');
            if (_Byte != '\0') {
                *_First = (widen((char) _Toupper(_Byte, &_Ctype)));
            }
        }

        return (const _Elem*) _First;
    }

    virtual _Elem __CLR_OR_THIS_CALL do_widen(char _Byte) const { // widen char
        return _Maklocchr(_Byte, static_cast<_Elem*>(nullptr), _Cvt);
    }

    virtual const char* __CLR_OR_THIS_CALL do_widen(
        const char* _First, const char* _Last, _Elem* _Dest) const { // widen chars in [_First, _Last)
        _Adl_verify_range(_First, _Last);
        for (; _First != _Last; ++_First, ++_Dest) {
            *_Dest = _Maklocchr(*_First, static_cast<_Elem*>(nullptr), _Cvt);
        }

        return _First;
    }

    char __CLR_OR_THIS_CALL _Donarrow(_Elem _Ch, char _Dflt) const { // narrow element to char
        char _Byte;
        if (_Ch == (_Elem) 0) {
            return '\0';
        }

        if ((_Byte = _Maklocbyte(_Ch, _Cvt)) == '\0') {
            return _Dflt;
        }

        return _Byte;
    }

    virtual char __CLR_OR_THIS_CALL do_narrow(_Elem _Ch, char _Dflt) const { // narrow element to char
        return _Donarrow(_Ch, _Dflt);
    }

    virtual const _Elem* __CLR_OR_THIS_CALL do_narrow(const _Elem* _First, const _Elem* _Last, char _Dflt,
        char* _Dest) const { // narrow elements in [_First, _Last) to chars
        _Adl_verify_range(_First, _Last);
        for (; _First != _Last; ++_First, ++_Dest) {
            *_Dest = _Donarrow(*_First, _Dflt);
        }

        return _First;
    }

private:
    _Locinfo::_Ctypevec _Ctype; // locale info passed to _Tolower, etc.
    _Locinfo::_Cvtvec _Cvt; // conversion information
};

// STATIC ctype::id OBJECT
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdllimport-static-field-def"
#endif // __clang__

template <class _Elem>
locale::id ctype<_Elem>::id;

#ifdef __clang__
#pragma clang diagnostic pop
#endif // __clang__

// CLASS ctype<char>
template <>
class _CRTIMP2_PURE_IMPORT ctype<char> : public ctype_base { // facet for classifying char elements, converting cases
public:
    using _Elem     = char;
    using char_type = _Elem;

    bool __CLR_OR_THIS_CALL is(mask _Maskval, _Elem _Ch) const { // test if element fits any mask classifications
        return (_Ctype._Table[(unsigned char) _Ch] & _Maskval) != 0;
    }

    const _Elem* __CLR_OR_THIS_CALL is(const _Elem* _First, const _Elem* _Last,
        mask* _Dest) const { // get mask sequence for elements in [_First, _Last)
        _Adl_verify_range(_First, _Last);
        for (; _First != _Last; ++_First, ++_Dest) {
            *_Dest = _Ctype._Table[(unsigned char) *_First];
        }

        return _First;
    }

    const _Elem* __CLR_OR_THIS_CALL scan_is(mask _Maskval, const _Elem* _First,
        const _Elem* _Last) const { // find first in [_First, _Last) that fits mask classification
        _Adl_verify_range(_First, _Last);
        while (_First != _Last && !is(_Maskval, *_First)) {
            ++_First;
        }

        return _First;
    }

    const _Elem* __CLR_OR_THIS_CALL scan_not(mask _Maskval, const _Elem* _First,
        const _Elem* _Last) const { // find first in [_First, _Last) not fitting mask classification
        _Adl_verify_range(_First, _Last);
        while (_First != _Last && is(_Maskval, *_First)) {
            ++_First;
        }

        return _First;
    }

    _Elem __CLR_OR_THIS_CALL tolower(_Elem _Ch) const { // convert element to lower case
        return do_tolower(_Ch);
    }

    const _Elem* __CLR_OR_THIS_CALL tolower(
        _Elem* _First, const _Elem* _Last) const { // convert [_First, _Last) in place to lower case
        return do_tolower(_First, _Last);
    }

    _Elem __CLR_OR_THIS_CALL toupper(_Elem _Ch) const { // convert element to upper case
        return do_toupper(_Ch);
    }

    const _Elem* __CLR_OR_THIS_CALL toupper(
        _Elem* _First, const _Elem* _Last) const { // convert [_First, _Last) in place to upper case
        return do_toupper(_First, _Last);
    }

    _Elem __CLR_OR_THIS_CALL widen(char _Byte) const { // widen char
        return do_widen(_Byte);
    }

    const _Elem* __CLR_OR_THIS_CALL widen(const char* _First, const char* _Last,
        _Elem* _Dest) const { // widen chars in [_First, _Last)
        return do_widen(_First, _Last, _Dest);
    }

    _Elem __CLR_OR_THIS_CALL narrow(_Elem _Ch, char _Dflt = '\0') const { // narrow element to char
        return do_narrow(_Ch, _Dflt);
    }

    const _Elem* __CLR_OR_THIS_CALL narrow(const _Elem* _First, const _Elem* _Last, char _Dflt,
        char* _Dest) const { // narrow elements in [_First, _Last) to chars
        return do_narrow(_First, _Last, _Dflt, _Dest);
    }

    __PURE_APPDOMAIN_GLOBAL static locale::id id;

    explicit __CLR_OR_THIS_CALL ctype(const mask* _Table = nullptr, bool _Deletetable = false,
        size_t _Refs = 0)
        : ctype_base(_Refs) { // construct with specified table and delete flag for table
        _BEGIN_LOCINFO(_Lobj)
        _Init(_Lobj);
        _END_LOCINFO()

        _Tidy(); // free existing table, as needed
        if (_Table != nullptr) { // replace existing char to mask table
            _Ctype._Table = _Table;
            _Ctype._Delfl = _Deletetable ? -1 : 0;
        } else { // use classic table
            _Ctype._Table = classic_table();
            _Ctype._Delfl = 0;
        }
    }

    __CLR_OR_THIS_CALL ctype(const _Locinfo& _Lobj, size_t _Refs = 0)
        : ctype_base(_Refs) { // construct from current locale
        _Init(_Lobj);
    }

    static size_t __CLRCALL_OR_CDECL _Getcat(const locale::facet** _Ppf = nullptr,
        const locale* _Ploc = nullptr) { // return locale category mask and construct standard facet
        if (_Ppf != nullptr && *_Ppf == nullptr) {
            *_Ppf = new ctype<_Elem>(_Locinfo(_Ploc->c_str()));
        }

        return _X_CTYPE;
    }

    const mask* __CLR_OR_THIS_CALL table() const noexcept { // return address of char to mask table
        return _Ctype._Table;
    }

    static const mask* __CLRCALL_OR_CDECL
        classic_table() noexcept { // return address of char to mask table for "C" locale
        return _STD use_facet<ctype>(locale::classic()).table();
    }

    _PGLOBAL static const size_t table_size = 1 << CHAR_BIT; // size of ctype mapping table, typically 256

protected:
    virtual __CLR_OR_THIS_CALL ~ctype() noexcept { // destroy the object
        _Tidy();
    }

    void __CLR_OR_THIS_CALL _Init(const _Locinfo& _Lobj) { // initialize from _Lobj
        _Ctype = _Lobj._Getctype();
    }

    void __CLR_OR_THIS_CALL _Tidy() noexcept { // free any allocated storage
        if (0 < _Ctype._Delfl) {
            _CSTD free((void*) _Ctype._Table);
        } else if (_Ctype._Delfl < 0) {
            delete[] _Ctype._Table;
        }

        _CSTD free(_Ctype._LocaleName);
    }

    virtual _Elem __CLR_OR_THIS_CALL do_tolower(_Elem _Ch) const { // convert element to lower case
        return (_Elem) _Tolower((unsigned char) _Ch, &_Ctype);
    }

    virtual const _Elem* __CLR_OR_THIS_CALL do_tolower(_Elem* _First,
        const _Elem* _Last) const { // convert [_First, _Last) in place to lower case
        _Adl_verify_range((const _Elem*) _First, _Last);
        for (; _First != _Last; ++_First) {
            *_First = (_Elem) _Tolower((unsigned char) *_First, &_Ctype);
        }

        return (const _Elem*) _First;
    }

    virtual _Elem __CLR_OR_THIS_CALL do_toupper(_Elem _Ch) const { // convert element to upper case
        return (_Elem) _Toupper((unsigned char) _Ch, &_Ctype);
    }

    virtual const _Elem* __CLR_OR_THIS_CALL do_toupper(_Elem* _First,
        const _Elem* _Last) const { // convert [_First, _Last) in place to upper case
        _Adl_verify_range((const _Elem*) _First, _Last);
        for (; _First != _Last; ++_First) {
            *_First = (_Elem) _Toupper((unsigned char) *_First, &_Ctype);
        }

        return (const _Elem*) _First;
    }

    virtual _Elem __CLR_OR_THIS_CALL do_widen(char _Byte) const { // widen char
        return _Byte;
    }

    virtual const _Elem* __CLR_OR_THIS_CALL do_widen(
        const char* _First, const char* _Last, _Elem* _Dest) const { // widen chars in [_First, _Last)
        _Adl_verify_range(_First, _Last);
        _CSTD memcpy(_Dest, _First, static_cast<size_t>(_Last - _First));
        return _Last;
    }

    virtual _Elem __CLR_OR_THIS_CALL do_narrow(_Elem _Ch, char) const { // narrow char
        return _Ch;
    }

    virtual const _Elem* __CLR_OR_THIS_CALL do_narrow(const _Elem* _First, const _Elem* _Last, char,
        char* _Dest) const { // narrow elements in [_First, _Last) to chars
        _Adl_verify_range(_First, _Last);
        _CSTD memcpy(_Dest, _First, static_cast<size_t>(_Last - _First));
        return _Last;
    }

private:
    _Locinfo::_Ctypevec _Ctype; // information
};

// CLASS ctype<wchar_t>
template <>
class _CRTIMP2_PURE_IMPORT ctype<wchar_t>
    : public ctype_base { // facet for classifying wchar_t elements, converting cases
public:
    using _Elem     = wchar_t;
    using char_type = _Elem;

    bool __CLR_OR_THIS_CALL is(mask _Maskval, _Elem _Ch) const { // test if element fits any mask classifications
        return do_is(_Maskval, _Ch);
    }

    const _Elem* __CLR_OR_THIS_CALL is(const _Elem* _First, const _Elem* _Last,
        mask* _Dest) const { // get mask sequence for elements in [_First, _Last)
        return do_is(_First, _Last, _Dest);
    }

    const _Elem* __CLR_OR_THIS_CALL scan_is(mask _Maskval, const _Elem* _First,
        const _Elem* _Last) const { // find first in [_First, _Last) that fits mask classification
        return do_scan_is(_Maskval, _First, _Last);
    }

    const _Elem* __CLR_OR_THIS_CALL scan_not(mask _Maskval, const _Elem* _First,
        const _Elem* _Last) const { // find first in [_First, _Last) not fitting mask classification
        return do_scan_not(_Maskval, _First, _Last);
    }

    _Elem __CLR_OR_THIS_CALL tolower(_Elem _Ch) const { // convert element to lower case
        return do_tolower(_Ch);
    }

    const _Elem* __CLR_OR_THIS_CALL tolower(
        _Elem* _First, const _Elem* _Last) const { // convert [_First, _Last) in place to lower case
        return do_tolower(_First, _Last);
    }

    _Elem __CLR_OR_THIS_CALL toupper(_Elem _Ch) const { // convert element to upper case
        return do_toupper(_Ch);
    }

    const _Elem* __CLR_OR_THIS_CALL toupper(
        _Elem* _First, const _Elem* _Last) const { // convert [_First, _Last) in place to upper case
        return do_toupper(_First, _Last);
    }

    _Elem __CLR_OR_THIS_CALL widen(char _Byte) const { // widen char
        return do_widen(_Byte);
    }

    const char* __CLR_OR_THIS_CALL widen(const char* _First, const char* _Last,
        _Elem* _Dest) const { // widen chars in [_First, _Last)
        return do_widen(_First, _Last, _Dest);
    }

    char __CLR_OR_THIS_CALL narrow(_Elem _Ch, char _Dflt = '\0') const { // narrow element to char
        return do_narrow(_Ch, _Dflt);
    }

    const _Elem* __CLR_OR_THIS_CALL narrow(const _Elem* _First, const _Elem* _Last, char _Dflt,
        char* _Dest) const { // narrow elements in [_First, _Last) to chars
        return do_narrow(_First, _Last, _Dflt, _Dest);
    }

    __PURE_APPDOMAIN_GLOBAL static locale::id id;

    explicit __CLR_OR_THIS_CALL ctype(size_t _Refs = 0) : ctype_base(_Refs) { // construct from current locale
        _BEGIN_LOCINFO(_Lobj)
        _Init(_Lobj);
        _END_LOCINFO()
    }

    __CLR_OR_THIS_CALL ctype(const _Locinfo& _Lobj, size_t _Refs = 0)
        : ctype_base(_Refs) { // construct from specified locale
        _Init(_Lobj);
    }

    static size_t __CLRCALL_OR_CDECL _Getcat(const locale::facet** _Ppf = nullptr,
        const locale* _Ploc = nullptr) { // return locale category mask and construct standard facet
        if (_Ppf != nullptr && *_Ppf == nullptr) {
            *_Ppf = new ctype<_Elem>(_Locinfo(_Ploc->c_str()));
        }

        return _X_CTYPE;
    }

protected:
    virtual __CLR_OR_THIS_CALL ~ctype() noexcept { // destroy the object
        if (_Ctype._Delfl) {
            _CSTD free((void*) _Ctype._Table);
        }

        _CSTD free(_Ctype._LocaleName);
    }

    void __CLR_OR_THIS_CALL _Init(const _Locinfo& _Lobj) { // initialize from _Lobj
        _Ctype = _Lobj._Getctype();
        _Cvt   = _Lobj._Getcvt();
    }

    virtual bool __CLR_OR_THIS_CALL do_is(
        mask _Maskval, _Elem _Ch) const { // test if element fits any mask classifications
        return (_CSTD _Getwctype(_Ch, &_Ctype) & _Maskval) != 0;
    }

    virtual const _Elem* __CLR_OR_THIS_CALL do_is(const _Elem* _First, const _Elem* _Last,
        mask* _Dest) const { // get mask sequence for elements in [_First, _Last)
        _Adl_verify_range(_First, _Last);
        return _CSTD _Getwctypes(_First, _Last, _Dest, &_Ctype);
    }

    virtual const _Elem* __CLR_OR_THIS_CALL do_scan_is(mask _Maskval, const _Elem* _First,
        const _Elem* _Last) const { // find first in [_First, _Last) that fits mask classification
        _Adl_verify_range(_First, _Last);
        while (_First != _Last && !is(_Maskval, *_First)) {
            ++_First;
        }

        return _First;
    }

    virtual const _Elem* __CLR_OR_THIS_CALL do_scan_not(mask _Maskval, const _Elem* _First,
        const _Elem* _Last) const { // find first in [_First, _Last) not fitting mask classification
        _Adl_verify_range(_First, _Last);
        while (_First != _Last && is(_Maskval, *_First)) {
            ++_First;
        }

        return _First;
    }

    virtual _Elem __CLR_OR_THIS_CALL do_tolower(_Elem _Ch) const { // convert element to lower case
        return _Towlower(_Ch, &_Ctype);
    }

    virtual const _Elem* __CLR_OR_THIS_CALL do_tolower(_Elem* _First,
        const _Elem* _Last) const { // convert [_First, _Last) in place to lower case
        _Adl_verify_range((const _Elem*) _First, _Last);
        for (; _First != _Last; ++_First) {
            *_First = _Towlower(*_First, &_Ctype);
        }

        return (const _Elem*) _First;
    }

    virtual _Elem __CLR_OR_THIS_CALL do_toupper(_Elem _Ch) const { // convert element to upper case
        return _Towupper(_Ch, &_Ctype);
    }

    virtual const _Elem* __CLR_OR_THIS_CALL do_toupper(_Elem* _First,
        const _Elem* _Last) const { // convert [_First, _Last) in place to upper case
        _Adl_verify_range((const _Elem*) _First, _Last);
        for (; _First != _Last; ++_First) {
            *_First = _Towupper(*_First, &_Ctype);
        }

        return (const _Elem*) _First;
    }

    _Elem __CLR_OR_THIS_CALL _Dowiden(char _Byte) const { // widen char
        mbstate_t _Mbst = {};
        wchar_t _Wc;
        return _Mbrtowc(&_Wc, &_Byte, 1, &_Mbst, &_Cvt) < 0 ? (wchar_t) WEOF : _Wc;
    }

    virtual _Elem __CLR_OR_THIS_CALL do_widen(char _Byte) const { // widen char
        return _Dowiden(_Byte);
    }

    virtual const char* __CLR_OR_THIS_CALL do_widen(
        const char* _First, const char* _Last, _Elem* _Dest) const { // widen chars in [_First, _Last)
        _Adl_verify_range(_First, _Last);
        for (; _First != _Last; ++_First, ++_Dest) {
            *_Dest = _Dowiden(*_First);
        }

        return _First;
    }

    char __CLR_OR_THIS_CALL _Donarrow(_Elem _Ch, char _Dflt) const { // narrow element to char
        char _Buf[MB_LEN_MAX];
        mbstate_t _Mbst = {};
        return _Wcrtomb(_Buf, _Ch, &_Mbst, &_Cvt) != 1 ? _Dflt : _Buf[0];
    }

    virtual char __CLR_OR_THIS_CALL do_narrow(_Elem _Ch, char _Dflt) const { // narrow element to char
        return _Donarrow(_Ch, _Dflt);
    }

    virtual const _Elem* __CLR_OR_THIS_CALL do_narrow(const _Elem* _First, const _Elem* _Last, char _Dflt,
        char* _Dest) const { // narrow elements in [_First, _Last) to chars
        _Adl_verify_range(_First, _Last);
        for (; _First != _Last; ++_First, ++_Dest) {
            *_Dest = _Donarrow(*_First, _Dflt);
        }

        return _First;
    }

private:
    _Locinfo::_Ctypevec _Ctype; // locale info passed to _Tolower, etc.
    _Locinfo::_Cvtvec _Cvt; // conversion information
};

#ifdef _NATIVE_WCHAR_T_DEFINED
// CLASS ctype<unsigned short>
template <>
class _CRTIMP2_PURE_IMPORT ctype<unsigned short>
    : public ctype_base { // facet for classifying unsigned short elements, converting cases
public:
    using _Elem     = unsigned short;
    using char_type = _Elem;

    bool __CLR_OR_THIS_CALL is(mask _Maskval, _Elem _Ch) const { // test if element fits any mask classifications
        return do_is(_Maskval, _Ch);
    }

    const _Elem* __CLR_OR_THIS_CALL is(const _Elem* _First, const _Elem* _Last,
        mask* _Dest) const { // get mask sequence for elements in [_First, _Last)
        return do_is(_First, _Last, _Dest);
    }

    const _Elem* __CLR_OR_THIS_CALL scan_is(mask _Maskval, const _Elem* _First,
        const _Elem* _Last) const { // find first in [_First, _Last) that fits mask classification
        return do_scan_is(_Maskval, _First, _Last);
    }

    const _Elem* __CLR_OR_THIS_CALL scan_not(mask _Maskval, const _Elem* _First,
        const _Elem* _Last) const { // find first in [_First, _Last) not fitting mask classification
        return do_scan_not(_Maskval, _First, _Last);
    }

    _Elem __CLR_OR_THIS_CALL tolower(_Elem _Ch) const { // convert element to lower case
        return do_tolower(_Ch);
    }

    const _Elem* __CLR_OR_THIS_CALL tolower(
        _Elem* _First, const _Elem* _Last) const { // convert [_First, _Last) in place to lower case
        return do_tolower(_First, _Last);
    }

    _Elem __CLR_OR_THIS_CALL toupper(_Elem _Ch) const { // convert element to upper case
        return do_toupper(_Ch);
    }

    const _Elem* __CLR_OR_THIS_CALL toupper(
        _Elem* _First, const _Elem* _Last) const { // convert [_First, _Last) in place to upper case
        return do_toupper(_First, _Last);
    }

    _Elem __CLR_OR_THIS_CALL widen(char _Byte) const { // widen char
        return do_widen(_Byte);
    }

    const char* __CLR_OR_THIS_CALL widen(const char* _First, const char* _Last,
        _Elem* _Dest) const { // widen chars in [_First, _Last)
        return do_widen(_First, _Last, _Dest);
    }

    char __CLR_OR_THIS_CALL narrow(_Elem _Ch, char _Dflt = '\0') const { // narrow element to char
        return do_narrow(_Ch, _Dflt);
    }

    const _Elem* __CLR_OR_THIS_CALL narrow(const _Elem* _First, const _Elem* _Last, char _Dflt,
        char* _Dest) const { // narrow elements in [_First, _Last) to chars
        return do_narrow(_First, _Last, _Dflt, _Dest);
    }

    __PURE_APPDOMAIN_GLOBAL static locale::id id;

    explicit __CLR_OR_THIS_CALL ctype(size_t _Refs = 0) : ctype_base(_Refs) { // construct from current locale
        _BEGIN_LOCINFO(_Lobj)
        _Init(_Lobj);
        _END_LOCINFO()
    }

    __CLR_OR_THIS_CALL ctype(const _Locinfo& _Lobj, size_t _Refs = 0)
        : ctype_base(_Refs) { // construct from specified locale
        _Init(_Lobj);
    }

    static size_t __CLRCALL_OR_CDECL _Getcat(const locale::facet** _Ppf = nullptr,
        const locale* _Ploc = nullptr) { // return locale category mask and construct standard facet
        if (_Ppf != nullptr && *_Ppf == nullptr) {
            *_Ppf = new ctype<_Elem>(_Locinfo(_Ploc->c_str()));
        }

        return _X_CTYPE;
    }

protected:
    virtual __CLR_OR_THIS_CALL ~ctype() noexcept { // destroy the object
        if (_Ctype._Delfl) {
            _CSTD free((void*) _Ctype._Table);
        }

        _CSTD free(_Ctype._LocaleName);
    }

    void __CLR_OR_THIS_CALL _Init(const _Locinfo& _Lobj) { // initialize from _Lobj
        _Ctype = _Lobj._Getctype();
        _Cvt   = _Lobj._Getcvt();
    }

    virtual bool __CLR_OR_THIS_CALL do_is(
        mask _Maskval, _Elem _Ch) const { // test if element fits any mask classifications
        return (_CSTD _Getwctype(_Ch, &_Ctype) & _Maskval) != 0;
    }

    virtual const _Elem* __CLR_OR_THIS_CALL do_is(const _Elem* _First, const _Elem* _Last,
        mask* _Dest) const { // get mask sequence for elements in [_First, _Last)
        _Adl_verify_range(_First, _Last);
        return (const _Elem*) _CSTD _Getwctypes((const wchar_t*) _First, (const wchar_t*) _Last, _Dest, &_Ctype);
    }

    virtual const _Elem* __CLR_OR_THIS_CALL do_scan_is(mask _Maskval, const _Elem* _First,
        const _Elem* _Last) const { // find first in [_First, _Last) that fits mask classification
        _Adl_verify_range(_First, _Last);
        while (_First != _Last && !is(_Maskval, *_First)) {
            ++_First;
        }

        return _First;
    }

    virtual const _Elem* __CLR_OR_THIS_CALL do_scan_not(mask _Maskval, const _Elem* _First,
        const _Elem* _Last) const { // find first in [_First, _Last) not fitting mask classification
        _Adl_verify_range(_First, _Last);
        while (_First != _Last && is(_Maskval, *_First)) {
            ++_First;
        }

        return _First;
    }

    virtual _Elem __CLR_OR_THIS_CALL do_tolower(_Elem _Ch) const { // convert element to lower case
        return _Towlower(_Ch, &_Ctype);
    }

    virtual const _Elem* __CLR_OR_THIS_CALL do_tolower(_Elem* _First,
        const _Elem* _Last) const { // convert [_First, _Last) in place to lower case
        _Adl_verify_range((const _Elem*) _First, _Last);
        for (; _First != _Last; ++_First) {
            *_First = _Towlower(*_First, &_Ctype);
        }

        return (const _Elem*) _First;
    }

    virtual _Elem __CLR_OR_THIS_CALL do_toupper(_Elem _Ch) const { // convert element to upper case
        return _Towupper(_Ch, &_Ctype);
    }

    virtual const _Elem* __CLR_OR_THIS_CALL do_toupper(_Elem* _First,
        const _Elem* _Last) const { // convert [_First, _Last) in place to upper case
        _Adl_verify_range((const _Elem*) _First, _Last);
        for (; _First != _Last; ++_First) {
            *_First = _Towupper(*_First, &_Ctype);
        }

        return (const _Elem*) _First;
    }

    _Elem __CLR_OR_THIS_CALL _Dowiden(char _Byte) const { // widen char
        mbstate_t _Mbst = {};
        unsigned short _Wc;
        return _Mbrtowc((wchar_t*) &_Wc, &_Byte, 1, &_Mbst, &_Cvt) < 0 ? (unsigned short) WEOF : _Wc;
    }

    virtual _Elem __CLR_OR_THIS_CALL do_widen(char _Byte) const { // widen char
        return _Dowiden(_Byte);
    }

    virtual const char* __CLR_OR_THIS_CALL do_widen(
        const char* _First, const char* _Last, _Elem* _Dest) const { // widen chars in [_First, _Last)
        _Adl_verify_range(_First, _Last);
        for (; _First != _Last; ++_First, ++_Dest) {
            *_Dest = _Dowiden(*_First);
        }

        return _First;
    }

    char __CLR_OR_THIS_CALL _Donarrow(_Elem _Ch, char _Dflt) const { // narrow element to char
        char _Buf[MB_LEN_MAX];
        mbstate_t _Mbst = {};
        return _Wcrtomb(_Buf, _Ch, &_Mbst, &_Cvt) != 1 ? _Dflt : _Buf[0];
    }

    virtual char __CLR_OR_THIS_CALL do_narrow(_Elem _Ch, char _Dflt) const { // narrow element to char
        return _Donarrow(_Ch, _Dflt);
    }

    virtual const _Elem* __CLR_OR_THIS_CALL do_narrow(const _Elem* _First, const _Elem* _Last, char _Dflt,
        char* _Dest) const { // narrow elements in [_First, _Last) to chars
        _Adl_verify_range(_First, _Last);
        for (; _First != _Last; ++_First, ++_Dest) {
            *_Dest = _Donarrow(*_First, _Dflt);
        }

        return _First;
    }

private:
    _Locinfo::_Ctypevec _Ctype; // locale info passed to _Tolower, etc.
    _Locinfo::_Cvtvec _Cvt; // conversion information
};
#endif // _NATIVE_WCHAR_T_DEFINED

// CLASS TEMPLATE ctype_byname
template <class _Elem>
class ctype_byname : public ctype<_Elem> { // ctype for named locale
public:
    static_assert(!_ENFORCE_FACET_SPECIALIZATIONS || _Is_any_of_v<_Elem, char, wchar_t>, _FACET_SPECIALIZATION_MESSAGE);

    explicit __CLR_OR_THIS_CALL ctype_byname(const char* _Locname, size_t _Refs = 0)
        : ctype<_Elem>(_Locinfo(_Locname), _Refs) { // construct for named locale
    }

    explicit __CLR_OR_THIS_CALL ctype_byname(const string& _Str, size_t _Refs = 0)
        : ctype<_Elem>(_Locinfo(_Str.c_str()), _Refs) { // construct for named locale
    }

protected:
    virtual __CLR_OR_THIS_CALL ~ctype_byname() noexcept { // destroy the object
    }
};

#if defined(_DLL_CPPLIB)

#if !defined(_CRTBLD) || defined(__FORCE_INSTANCE)
template class _CRTIMP2_PURE_IMPORT codecvt<char, char, _Mbstatet>;
#endif // !defined(_CRTBLD) || defined(__FORCE_INSTANCE)
#endif // defined(_DLL_CPPLIB)
_STD_END
#pragma pop_macro("new")
_STL_RESTORE_CLANG_WARNINGS
#pragma warning(pop)
#pragma pack(pop)
#endif // RC_INVOKED
#endif // _XLOCALE_

/*
 * Copyright (c) by P.J. Plauger. All rights reserved.
 * Consult your license regarding permissions and restrictions.
V6.50:0009 */
